<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.3.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chuangges.gitee.io","root":"/","scheme":"Pisces","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="开发技术、版本优化、组件开发、组件通信">
<meta property="og:type" content="article">
<meta property="og:title" content="Vue3 项目开发">
<meta property="og:url" content="https://chuangges.gitee.io/2023/03/02/21-vue3%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/index.html">
<meta property="og:site_name" content="闯哥要去流浪了">
<meta property="og:description" content="开发技术、版本优化、组件开发、组件通信">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-03-02T07:26:59.000Z">
<meta property="article:modified_time" content="2023-10-12T07:55:11.103Z">
<meta property="article:author" content="chuangges">
<meta property="article:tag" content="JS 框架">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://chuangges.gitee.io/2023/03/02/21-vue3%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Vue3 项目开发 | 闯哥要去流浪了</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="闯哥要去流浪了" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">闯哥要去流浪了</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">愿你岁月可回首，且以深情共白头</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chuangges.gitee.io/2023/03/02/21-vue3%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/chuang.png">
      <meta itemprop="name" content="chuangges">
      <meta itemprop="description" content="chuangge's blog.">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="闯哥要去流浪了">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Vue3 项目开发
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2023-03-02 15:26:59" itemprop="dateCreated datePublished" datetime="2023-03-02T15:26:59+08:00">2023-03-02</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2023-10-12 15:55:11" itemprop="dateModified" datetime="2023-10-12T15:55:11+08:00">2023-10-12</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JS-%E6%A1%86%E6%9E%B6/" itemprop="url" rel="index"><span itemprop="name">JS 框架</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>54k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>49 分钟</span>
            </span>
            <div class="post-description">开发技术、版本优化、组件开发、组件通信</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、项目构建"><a href="#一、项目构建" class="headerlink" title="一、项目构建"></a>一、项目构建</h1><h2 id="构建工具"><a href="#构建工具" class="headerlink" title="构建工具"></a>构建工具</h2><ul>
<li><code>Webpack</code>：启动后从入口开始逐步进行语法解析、依赖收集、代码转译、打包合并、代码优化等一系列操作，最终将高版本、离散的源码编译打包成低版本、高兼容的代码。</li>
<li><code>Vite</code>：支持本地快速冷启动、热更新和按需编译的非打包服务器。启动后将应用模块划分为依赖和源码并基于 esbuild 进行依赖预构建，浏览器请求模块时才解析 esmodule 源码，同时还可通过路由懒加载实现按需加载。注意打包到生产环境时需要通过 rollup。</li>
</ul>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、vue3 + vite：官方推荐</span></span><br><span class="line">npm init vue@latest</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、vite：基于 vite 小而巧的打包方案，可选择 vue/react</span></span><br><span class="line">npm init vite@latest</span><br><span class="line">pnpm create vite</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、vue-cli3：基于 webpack 大而全的打包工具</span></span><br><span class="line">npm update -g @vue/cli  </span><br><span class="line">vue create &lt;name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 弃用命令</span></span><br><span class="line">npm init vite-app &lt;name&gt;    <span class="comment">// vite1.x</span></span><br><span class="line">npm init @vitejs/app        <span class="comment">// vite2.x</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// package.json 命令</span></span><br><span class="line"><span class="string">&quot;script&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;serve:test&quot;</span>: <span class="string">&quot;vite --mode test&quot;</span>,</span><br><span class="line">    <span class="string">&quot;build&quot;</span>: <span class="string">&quot;vue-tsc --noEmit &amp;&amp; vite build&quot;</span>,</span><br><span class="line">    <span class="string">&quot;build:test&quot;</span>: <span class="string">&quot;vue-tsc --noEmit &amp;&amp; vite build --mode test&quot;</span>,</span><br><span class="line">    <span class="string">&quot;serve&quot;</span>: <span class="string">&quot;vite preview --host&quot;</span>  <span class="comment">// 显示 Network 地址</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 项目运行：通过 main.js 将 App.vue 渲染到 index.html 的指定区域</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> App.vue：编写待渲染模板的项目根组件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> index.html：预留一个 el 区域的唯一 HTML</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> main.js：将模版渲染到预留区域的打包入口文件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> env.d.ts：为自定义的环境变量增加智能提示</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 优先级从低到高：.env、.env.local、.env.[mode]、.env.[mode].local</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> Vscode 插件防止红线：Volar、Vue3 Snippets、TypeScript Vue Plugin</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// vite.config.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; defineConfig &#125; <span class="keyword">from</span> <span class="string">&#x27;vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> vue <span class="keyword">from</span> <span class="string">&#x27;@vitejs/plugin-vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> legacy <span class="keyword">from</span> <span class="string">&#x27;@vitejs/plugin-legacy&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; viteMockServe &#125; <span class="keyword">from</span> <span class="string">&#x27;vite-plugin-mock&#x27;</span></span><br><span class="line"><span class="keyword">import</span> viteCompression <span class="keyword">from</span> <span class="string">&#x27;vite-plugin-compression&#x27;</span></span><br><span class="line"><span class="comment">// 组件自动按需注册：vite.config.js 集成插件 unplugin-vue-components</span></span><br><span class="line"><span class="keyword">import</span> &#123; defineConfig &#125; <span class="keyword">from</span> <span class="string">&#x27;vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">AutoComponents</span> <span class="keyword">from</span> <span class="string">&#x27;unplugin-vue-components/vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">ElementPlusResolver</span>, <span class="title class_">AntDesignVueResolver</span></span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&#x27;unplugin-vue-components/resolvers&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Icons</span> <span class="keyword">from</span> <span class="string">&#x27;unplugin-icons/vite&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">IconsResolver</span> <span class="keyword">from</span> <span class="string">&#x27;unplugin-icons/resolver&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">AutoImport</span> <span class="keyword">from</span> <span class="string">&#x27;unplugin-auto-import/vite&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>(&#123;</span><br><span class="line">  <span class="attr">resolve</span>: &#123;        <span class="comment">// 路径别名、扩展</span></span><br><span class="line">      <span class="attr">alias</span>: &#123; <span class="string">&quot;@&quot;</span>: <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>).<span class="title function_">resolve</span>(__dirname, <span class="string">&quot;src&quot;</span>)&#125;,</span><br><span class="line">      <span class="attr">extensions</span>: [<span class="string">&#x27;.js&#x27;</span>, <span class="string">&#x27;.ts&#x27;</span>, <span class="string">&#x27;.jsx&#x27;</span>, <span class="string">&#x27;.tsx&#x27;</span>, <span class="string">&#x27;.json&#x27;</span>, <span class="string">&#x27;.vue&#x27;</span>]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">server</span>: &#123;</span><br><span class="line">      <span class="attr">host</span>: <span class="string">&#x27;0.0.0.0&#x27;</span>,</span><br><span class="line">      <span class="attr">port</span>: <span class="string">&#x27;3000&#x27;</span>,</span><br><span class="line">      <span class="attr">proxy</span>: &#123;</span><br><span class="line">          <span class="comment">// 字符串简写写法</span></span><br><span class="line">          <span class="string">&#x27;/foo&#x27;</span>: <span class="string">&#x27;http://localhost:4567&#x27;</span>,</span><br><span class="line">          <span class="comment">// 选项写法</span></span><br><span class="line">          <span class="string">&#x27;/api&#x27;</span>: &#123;</span><br><span class="line">              <span class="attr">target</span>: <span class="string">&#x27;http://jsonplaceholder.typicode.com&#x27;</span>,</span><br><span class="line">              <span class="attr">changeOrigin</span>: <span class="literal">true</span>,</span><br><span class="line">              <span class="attr">rewrite</span>: <span class="function">(<span class="params">path</span>) =&gt;</span> path.<span class="title function_">replace</span>(<span class="regexp">/^\/api/</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="comment">// 正则表达式写法</span></span><br><span class="line">          <span class="string">&#x27;^/fallback/.*&#x27;</span>: &#123;</span><br><span class="line">              <span class="attr">target</span>: <span class="string">&#x27;http://jsonplaceholder.typicode.com&#x27;</span>,</span><br><span class="line">              <span class="attr">changeOrigin</span>: <span class="literal">true</span>,</span><br><span class="line">              <span class="attr">rewrite</span>: <span class="function">(<span class="params">path</span>) =&gt;</span> path.<span class="title function_">replace</span>(<span class="regexp">/^\/fallback/</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="comment">// 使用 proxy 实例</span></span><br><span class="line">          <span class="string">&#x27;/api&#x27;</span>: &#123;</span><br><span class="line">              <span class="attr">target</span>: <span class="string">&#x27;http://jsonplaceholder.typicode.com&#x27;</span>,</span><br><span class="line">              <span class="attr">changeOrigin</span>: <span class="literal">true</span>,</span><br><span class="line">              <span class="attr">configure</span>: <span class="function">(<span class="params">proxy, options</span>) =&gt;</span> &#123; &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="comment">// 代理 WebSocket、socket</span></span><br><span class="line">          <span class="string">&#x27;/socket.io&#x27;</span>: &#123;</span><br><span class="line">              <span class="attr">target</span>: <span class="string">&#x27;ws://localhost:3000&#x27;</span>,</span><br><span class="line">              <span class="attr">ws</span>: <span class="literal">true</span></span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">build</span>: &#123; <span class="attr">target</span>: <span class="string">&#x27;es2015&#x27;</span>, <span class="attr">cssTarget</span>: <span class="string">&#x27;chrome49&#x27;</span> &#125;,  <span class="comment">// JS、css 兼容</span></span><br><span class="line">  <span class="attr">css</span>: &#123;   </span><br><span class="line">      <span class="attr">preprocessorOptions</span>: &#123;       <span class="comment">// 自动引入全局 scss</span></span><br><span class="line">          <span class="attr">scss</span>: &#123;<span class="attr">additionalData</span>: <span class="string">&#x27;@import &quot;./src/styles/global.scss&quot;&#x27;</span>&#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">postcss</span>: &#123;</span><br><span class="line">          <span class="attr">plugins</span>: [</span><br><span class="line">              <span class="title function_">require</span>(<span class="params"><span class="string">&#x27;autoprefixer&#x27;</span></span>)&#123;</span><br><span class="line">                  <span class="attr">browsers</span>: [<span class="string">&#x27;Android &gt;= 4.0&#x27;</span>, <span class="string">&#x27;iOS &gt;= 7&#x27;</span>]</span><br><span class="line">              &#125;,</span><br><span class="line">              <span class="title function_">require</span>(<span class="params"><span class="string">&#x27;postcss-pxtorem&#x27;</span></span>)&#123;</span><br><span class="line">                  <span class="attr">rootValue</span>: <span class="number">75</span>, <span class="attr">propList</span>: [<span class="string">&#x27;*&#x27;</span>]</span><br><span class="line">              &#125;,</span><br><span class="line">              &#123;   <span class="comment">// 移除 element-plus 打包时 @charset 警告</span></span><br><span class="line">                  <span class="attr">postcssPlugin</span>: <span class="string">&#x27;internal:charset-removal&#x27;</span>,</span><br><span class="line">                  <span class="title class_">AtRule</span>: &#123;</span><br><span class="line">                      <span class="attr">charset</span>: <span class="function">(<span class="params">atRule</span>) =&gt;</span> &#123;</span><br><span class="line">                          <span class="keyword">if</span> (atRule.<span class="property">name</span> === <span class="string">&#x27;charset&#x27;</span>) &#123;</span><br><span class="line">                              atRule.<span class="title function_">remove</span>();</span><br><span class="line">                          &#125;</span><br><span class="line">                      &#125;</span><br><span class="line">                  &#125;</span><br><span class="line">              &#125;</span><br><span class="line"></span><br><span class="line">          ]</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">      <span class="title function_">vue</span>(), </span><br><span class="line">      <span class="title function_">legacy</span>(&#123;     <span class="comment">// 兼容浏览器</span></span><br><span class="line">          <span class="attr">targets</span>: [<span class="string">&#x27;chrome 49&#x27;</span>], </span><br><span class="line">          <span class="attr">modernPolyfills</span>: [<span class="string">&#x27;es.global-this&#x27;</span>],</span><br><span class="line">          <span class="attr">additionalLegacyPolyfills</span>: [<span class="string">&#x27;regenerator-runtime/runtime&#x27;</span>]</span><br><span class="line">      &#125;),</span><br><span class="line">      <span class="title function_">viteMockServe</span>(&#123;          <span class="comment">// 模拟数据</span></span><br><span class="line">          <span class="attr">mockPath</span>: <span class="string">&quot;./src/mock/source&quot;</span>,</span><br><span class="line">          <span class="attr">localEnabled</span>: <span class="literal">true</span>,  <span class="comment">// 开发环境打开</span></span><br><span class="line">          <span class="attr">prodEnabled</span>: <span class="literal">false</span>,  <span class="comment">// 生产环境关闭</span></span><br><span class="line">          <span class="attr">supportTs</span>: <span class="literal">true</span>,     <span class="comment">// 打开则⽆法监听 js</span></span><br><span class="line">          <span class="attr">watchFiles</span>: <span class="literal">true</span>,    <span class="comment">// ⽂件更改则重新加载</span></span><br><span class="line">      &#125;),</span><br><span class="line">      <span class="title function_">viteCompression</span>(&#123;</span><br><span class="line">          <span class="attr">verbose</span>: <span class="literal">true</span>,       <span class="comment">// 默认即可</span></span><br><span class="line">          <span class="attr">disable</span>: <span class="literal">false</span>,      <span class="comment">// 开启压缩，默认即可</span></span><br><span class="line">          <span class="attr">deleteOriginFile</span>: <span class="literal">false</span>,   <span class="comment">// 删除源文件</span></span><br><span class="line">          <span class="attr">threshold</span>: <span class="number">10240</span>,    <span class="comment">// 压缩前最小文件大小</span></span><br><span class="line">          <span class="attr">algorithm</span>: <span class="string">&#x27;gzip&#x27;</span>,   <span class="comment">// 压缩算法</span></span><br><span class="line">          <span class="attr">ext</span>: <span class="string">&#x27;.gz&#x27;</span>,          <span class="comment">// 文件类型</span></span><br><span class="line">      &#125;),</span><br><span class="line">      <span class="title class_">AutoComponents</span>(&#123;     <span class="comment">// 自动按需导入组件：unplugin-vue-components</span></span><br><span class="line">          <span class="attr">dts</span>: <span class="string">&#x27;src/auto-components.d.ts&#x27;</span>,</span><br><span class="line">          <span class="attr">resolvers</span>: [</span><br><span class="line">              <span class="title class_">ElementPlusResolver</span>(), </span><br><span class="line">              <span class="title class_">AntDesignVueResolver</span>(),</span><br><span class="line">              <span class="title class_">IconsResolver</span>()</span><br><span class="line">          ]</span><br><span class="line">      &#125;),</span><br><span class="line">      <span class="title class_">Icons</span>(),               <span class="comment">// 自动导入图标：unplugin-icons</span></span><br><span class="line">      <span class="title class_">AutoImport</span>(&#123;           <span class="comment">// 自动按需导入 API：unplugin-auto-import</span></span><br><span class="line">          <span class="attr">include</span>: [<span class="regexp">/\.ts$/</span>, <span class="regexp">/\.vue$/</span>, <span class="regexp">/\.md$/</span>],     <span class="comment">// 自动导入的文件</span></span><br><span class="line">          <span class="attr">imports</span>: [<span class="string">&#x27;vue&#x27;</span>, <span class="string">&#x27;vue-router&#x27;</span>,            <span class="comment">// 全局导入的 api</span></span><br><span class="line">              &#123; <span class="string">&#x27;~store/user&#x27;</span>: [<span class="string">&#x27;useUserStore&#x27;</span>] &#125;,      <span class="comment">// 自定义模块</span></span><br><span class="line">          ],</span><br><span class="line">          <span class="attr">dts</span>: <span class="string">&#x27;src/auto-import.d.ts&#x27;</span>,    <span class="comment">// 兼容 ts 检查的自动生成文件</span></span><br><span class="line">          <span class="attr">eslintrc</span>: &#123;                        <span class="comment">// 兼容 eslint 检查的文件</span></span><br><span class="line">              <span class="attr">enabled</span>: <span class="literal">true</span>,</span><br><span class="line">              <span class="attr">filepath</span>: <span class="string">&#x27;./.eslintrc-auto-import.json&#x27;</span>,</span><br><span class="line">              <span class="attr">globalsPropValue</span>: <span class="literal">true</span>,</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="comment">// eslintrc.js：extends: [&#x27;./.eslintrc-auto-import.json&#x27;]</span></span><br><span class="line">          <span class="comment">// .eslintignore：src/auto-import.d.ts</span></span><br><span class="line">      &#125;),</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// tsconfig.json </span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;compilerOptions&quot;</span>: &#123;</span><br><span class="line">      <span class="string">&quot;baseUrl&quot;</span>: <span class="string">&quot;./&quot;</span>,                <span class="comment">// 路径前缀</span></span><br><span class="line">      <span class="string">&quot;target&quot;</span>: <span class="string">&quot;ES6&quot;</span>,                <span class="comment">// 生成版本</span></span><br><span class="line">      <span class="string">&quot;module&quot;</span>: <span class="string">&quot;commonjs&quot;</span>,           <span class="comment">// 加载器</span></span><br><span class="line">      <span class="string">&quot;paths&quot;</span>: &#123; <span class="string">&quot;@/*&quot;</span>: [ <span class="string">&quot;src/*&quot;</span> ],  <span class="comment">// 路径别名：npm i -D @types/node</span></span><br><span class="line">      <span class="string">&quot;types&quot;</span>: [</span><br><span class="line">          <span class="string">&#x27;vite-plugin-pages/client&#x27;</span>, </span><br><span class="line">          <span class="string">&#x27;vite-plugin-vue-layouts/client&#x27;</span>,</span><br><span class="line">          <span class="string">&#x27;unplugin-icons/types/vue3&#x27;</span></span><br><span class="line">      ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="string">&quot;exclude&quot;</span>: [<span class="string">&quot;node_modules&quot;</span>],        <span class="comment">// 不编译的目录</span></span><br><span class="line">  <span class="string">&quot;include&quot;</span>: [                        <span class="comment">// 编译文件</span></span><br><span class="line">      <span class="string">&quot;src/**/*.ts&quot;</span>,</span><br><span class="line">      <span class="string">&quot;src/**/*.d.ts&quot;</span>,</span><br><span class="line">      <span class="string">&quot;src/**/*.tsx&quot;</span>,</span><br><span class="line">      <span class="string">&quot;src/**/*.vue&quot;</span>,</span><br><span class="line">      <span class="string">&quot;*.ts&quot;</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// src/env.d.ts：使用时 import.meta.env.VITE_APP_BASE_URL</span></span><br><span class="line">interface <span class="title class_">ImportMetaEnv</span> &#123;</span><br><span class="line">    readonly <span class="attr">VITE_APP_BASE_URL</span>: string;    <span class="comment">// 接口请求地址</span></span><br><span class="line">    readonly <span class="attr">VITE_APP_STATIC_URL</span>: string;  <span class="comment">// 静态资源地址</span></span><br><span class="line">    readonly <span class="attr">VITE_PUBLIC_URL</span>: string;      <span class="comment">// 公共资源地址</span></span><br><span class="line">&#125;</span><br><span class="line">declare <span class="variable language_">module</span> <span class="string">&#x27;*.vue&#x27;</span> &#123;  <span class="comment">// 解决 ts 无法识别 vue 模块的问题</span></span><br><span class="line">    <span class="keyword">import</span> type &#123; <span class="title class_">DefineComponent</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line">    <span class="keyword">const</span> <span class="attr">component</span>: <span class="title class_">DefineComponent</span>&lt;&#123;&#125;, &#123;&#125;, any&gt;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">default</span> component</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// auto-components.d.ts</span></span><br><span class="line">declare <span class="variable language_">module</span> <span class="string">&#x27;vue&#x27;</span> &#123;</span><br><span class="line">  <span class="keyword">export</span> interface <span class="title class_">GlobalComponents</span> &#123;</span><br><span class="line">    <span class="title class_">IMdiAbTesting</span>: <span class="keyword">typeof</span> <span class="title function_">import</span>(<span class="string">&#x27;~icons/mdi/ab-testing&#x27;</span>)[<span class="string">&#x27;default&#x27;</span>]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="CSS-样式"><a href="#CSS-样式" class="headerlink" title="CSS 样式"></a>CSS 样式</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 样式方案</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Vue3 特性：变量、模块化 scoped module、选择器、绑定变量</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 样式穿透：css &gt;&gt;&gt;、scss :deep、废弃选择器 /deep/ ::v-deep</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Scss 预处理：pnpm add sass、vite.config.js、&lt;style lang=&quot;scss&quot;&gt;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> normalize.css：提供跨浏览器的统一初始化样式，并修复了浏览器的 bug</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> TailwindCSS：一个基于原子化理念命名、功能类优先的样式框架</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">:root &#123; --bg-<span class="attr">color</span>: #<span class="number">666</span>; &#125;</span><br><span class="line">.<span class="property">wrap</span> &#123; --<span class="attr">color</span>: blue; &#125;</span><br><span class="line">:<span class="title function_">global</span>(<span class="params">.red</span>) &#123; &#125;             <span class="comment">// 全局选择器</span></span><br><span class="line">.<span class="property">box</span> :<span class="title function_">deep</span>(<span class="params">.item</span>) &#123; &#125;         <span class="comment">// 深度选择器：影响子组件</span></span><br><span class="line">:<span class="title function_">slotted</span>(<span class="params">.red</span>) &#123; &#125;            <span class="comment">// 插槽选择器：影响 slot</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// main.js</span></span><br><span class="line">npm install normalize.<span class="property">css</span> css-loader style-loader --save</span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;normalize.css/normalize.css&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// v-bind 状态驱动实现主题切换</span></span><br><span class="line">&lt;script setup&gt;</span><br><span class="line">    <span class="keyword">import</span> &#123; reactive &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line">    <span class="keyword">const</span> redColor = <span class="title function_">ref</span>(<span class="string">&#x27;red&#x27;</span>)</span><br><span class="line">    <span class="keyword">const</span> theme = <span class="title function_">reactive</span>(&#123;&#125;)</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setWhiteTheme</span>(<span class="params"></span>) &#123;</span><br><span class="line">        theme.<span class="property">color</span> = <span class="string">&#x27;#000&#x27;</span></span><br><span class="line">        theme.<span class="property">backgroundColor</span> = <span class="string">&#x27;#fff&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setBlackTheme</span>(<span class="params"></span>) &#123;</span><br><span class="line">        theme.<span class="property">color</span> = <span class="string">&#x27;#fff&#x27;</span></span><br><span class="line">        theme.<span class="property">backgroundColor</span> = <span class="string">&#x27;#000&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="language-css"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="selector-class">.content</span> &#123;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        <span class="attribute">color</span>: <span class="built_in">v-bind</span>(redColor);</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        <span class="attribute">color</span>: <span class="built_in">v-bind</span>(<span class="string">&#x27;theme.color&#x27;</span>);</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        <span class="attribute">background</span>: <span class="built_in">v-bind</span>(<span class="string">&#x27;theme.backgroundColor&#x27;</span>);</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Scoped CSS：VueLoader 默认的模块化方案，为元素增加唯一属性 data-v-hash</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;scss&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="language-css">   </span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="selector-class">.outer</span> &#123; </span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        <span class="attribute">color</span>: <span class="built_in">var</span>(--color);             // 局部变量</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        <span class="attribute">background</span>: <span class="built_in">var</span>(--bg-color);     // 全局变量</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        :<span class="built_in">deep</span>(.el-input__inner) &#123; // <span class="selector-class">.outer</span><span class="selector-attr">[data-v-x]</span> <span class="selector-class">.el-input__inner</span></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">            <span class="attribute">background</span>: red;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">        &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// CSS Module：Scoped 替代方案，通过 config 命名规则生成唯一类名实现隔离</span></span><br><span class="line"><span class="comment">// tsconfig.json：模块插件安装后集成到项目</span></span><br><span class="line"><span class="attr">compilerOptions</span>: &#123;</span><br><span class="line">    <span class="string">&quot;plugins&quot;</span>: [&#123;<span class="string">&quot;name&quot;</span>: <span class="string">&quot;typescript-plugin-css-modules&quot;</span>&#125;]</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// .vscode/settings.json：VSCode 模块类名的智能提示</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="string">&quot;typescript.tsdk&quot;</span>: <span class="string">&quot;node_modules/typescript/lib&quot;</span>,</span><br><span class="line">    <span class="string">&quot;typescript.enablePromptUseWorkspaceTsdk&quot;</span>: <span class="literal">true</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// vue 组件使用</span></span><br><span class="line">&lt;script setup&gt;</span><br><span class="line">    <span class="keyword">import</span> &#123; useCssModule &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line">    <span class="comment">// 获取 style module 代码块编译后的 css 类对象，默认为 $style</span></span><br><span class="line">    <span class="keyword">const</span> style = <span class="title function_">useCssModule</span>()</span><br><span class="line">    <span class="keyword">const</span> zsStyle = <span class="title function_">useCssModule</span>(<span class="string">&#x27;zs&#x27;</span>)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;$style.red&quot;</span>&gt;</span>默认<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;style.success&quot;</span>&gt;</span>默认<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;zsStyle.success&quot;</span>&gt;</span>具名<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;zs.success&quot;</span>&gt;</span>具名<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;[zs.red,zs.border]&quot;</span>&gt;</span>具名<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">module</span>&gt;</span><span class="language-css"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="selector-class">.red</span> &#123; <span class="attribute">color</span>: pink; &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">module</span>=<span class="string">&quot;zs&quot;</span>&gt;</span><span class="language-css"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="selector-class">.success</span> &#123; <span class="attribute">color</span>: blue; &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="selector-class">.border</span>&#123; <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#ccc</span>; &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br><span class="line"><span class="comment">// Jsx、Tsx 组件使用</span></span><br><span class="line"><span class="attr">cell</span>: <span class="function">(<span class="params">h, &#123; col, row &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&#123;style.name&#125;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&#123;testImage&#125;</span> <span class="attr">class</span>=<span class="string">&#123;style[</span>&#x27;<span class="attr">name-img</span>&#x27;]&#125; /&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&#123;style[</span>&#x27;<span class="attr">name-text</span>&#x27;]&#125;&gt;</span>&#123;row.name&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">    )</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="title function_">render</span>(<span class="params">h</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&#123;this.$style.span&#125;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="Route-路由"><a href="#Route-路由" class="headerlink" title="Route 路由"></a>Route 路由</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// @types 插件使用 ts：npm install nprogress @types/nprogress -D</span></span><br><span class="line"><span class="keyword">import</span> storage <span class="keyword">from</span> <span class="string">&#x27;store&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">NProgress</span> <span class="keyword">from</span> <span class="string">&#x27;nprogress&#x27;</span>; </span><br><span class="line"><span class="keyword">import</span> &#123; createRouter, createWebHistory &#125; <span class="keyword">from</span> <span class="string">&quot;vue-router&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;nprogress/nprogress.css&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> router = <span class="title function_">createRouter</span>(&#123;</span><br><span class="line">    <span class="attr">history</span>: <span class="title function_">createWebHistory</span>(),  <span class="comment">// hash 模式：兼容性好但带 #</span></span><br><span class="line">    <span class="attr">routes</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="attr">path</span>: <span class="string">&#x27;/&#x27;</span>,</span><br><span class="line">            <span class="attr">redirect</span>: <span class="string">&#x27;/user&#x27;</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="attr">component</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;../pages/home.vue&#x27;</span>),</span><br><span class="line">            <span class="attr">name</span>: <span class="string">&#x27;home&#x27;</span>,</span><br><span class="line">            <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>,</span><br><span class="line">            <span class="attr">props</span>: <span class="literal">true</span>,</span><br><span class="line">            <span class="attr">meta</span>: &#123; <span class="attr">auth</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">            <span class="attr">beforeEnter</span>: <span class="function">(<span class="params">to, <span class="keyword">from</span></span>) =&gt;</span> &#123; <span class="keyword">return</span> <span class="literal">false</span> &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="attr">component</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;../pages/user.vue&#x27;</span>),</span><br><span class="line">            <span class="attr">name</span>: <span class="string">&#x27;user&#x27;</span>,</span><br><span class="line">            <span class="attr">alias</span>: <span class="string">&#x27;/users&#x27;</span>,</span><br><span class="line">            <span class="attr">path</span>: <span class="string">&#x27;/user/:name?&#x27;</span>,</span><br><span class="line">            <span class="attr">children</span>: [&#123;</span><br><span class="line">                <span class="attr">name</span>: <span class="string">&#x27;user1&#x27;</span>,</span><br><span class="line">                <span class="attr">path</span>: <span class="string">&#x27;user1&#x27;</span>,   <span class="comment">// 子组件的 path 不带 /  </span></span><br><span class="line">                <span class="attr">component</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;../pages/user1.vue&#x27;</span>)</span><br><span class="line">            &#125;]</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> registerRouteFresh = <span class="literal">true</span>;  <span class="comment">// 首次挂载时加载动态路由</span></span><br><span class="line">router.<span class="title function_">beforeEach</span>(<span class="keyword">async</span> (to, <span class="keyword">from</span>, next) =&gt; &#123;</span><br><span class="line">    <span class="title class_">NProgress</span>.<span class="title function_">start</span>();</span><br><span class="line">    <span class="keyword">let</span> isAuth = to.<span class="property">matched</span>.<span class="title function_">some</span>(<span class="function"><span class="params">r</span> =&gt;</span> r.<span class="property">meta</span>.<span class="property">auth</span>)</span><br><span class="line">    <span class="keyword">if</span> (storage.<span class="title function_">get</span>(<span class="string">&#x27;TOKEN&#x27;</span>) || isAuth) &#123;</span><br><span class="line">        <span class="title function_">next</span>()</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (registerRouteFresh) &#123;</span><br><span class="line">        <span class="keyword">let</span> <span class="title class_">NewRoutes</span> = <span class="keyword">await</span> <span class="title function_">getMenuNav</span>();</span><br><span class="line">        <span class="title class_">NewRoutes</span>.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">            router.<span class="title function_">addRoute</span>(item);</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="title function_">next</span>(&#123; ...to, <span class="attr">replace</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">        registerRouteFresh = <span class="literal">false</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="title function_">next</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;Login&#x27;</span>, <span class="attr">query</span>: &#123; <span class="attr">redirect</span>: to.<span class="property">fullPath</span> &#125; &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line">router.<span class="title function_">afterEach</span>(<span class="function">(<span class="params">to</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="title class_">NProgress</span>.<span class="title function_">done</span>();</span><br><span class="line">    <span class="title function_">setTitle</span>(to.<span class="property">meta</span>.<span class="property">title</span> <span class="keyword">as</span> string);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">configure</span>(&#123;</span><br><span class="line">    <span class="attr">showSpinner</span>: <span class="literal">true</span>,    <span class="comment">// 进度环</span></span><br><span class="line">    <span class="attr">easing</span>: <span class="string">&#x27;ease&#x27;</span>,       <span class="comment">// 动画效果</span></span><br><span class="line">    <span class="attr">speed</span>: <span class="number">500</span>,           <span class="comment">// 动画速度</span></span><br><span class="line">    <span class="attr">minimum</span>: <span class="number">0.3</span>,         <span class="comment">// 最低百分比</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">setTitle</span>(<span class="params">title?: string</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">VITE_APP_TITLE</span> &#125; = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">env</span>;</span><br><span class="line">    <span class="keyword">const</span> processTitle = <span class="variable constant_">VITE_APP_TITLE</span> || <span class="string">&#x27;X-BUILD&#x27;</span>;</span><br><span class="line">    <span class="variable language_">window</span>.<span class="property">document</span>.<span class="property">title</span> = <span class="string">`<span class="subst">$&#123;title | processTitle&#125;</span>`</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">createApp</span>(<span class="title class_">App</span>).<span class="title function_">use</span>(router).<span class="title function_">mount</span>(<span class="string">&#x27;#app&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&lt;router-view /&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">router-view</span> <span class="attr">name</span>=<span class="string">&quot;home&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">&quot;/home&quot;</span>&gt;</span>home页面<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">&quot;/user/tom&quot;</span>&gt;</span>传递 name<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">&quot;/user/user1&quot;</span>&gt;</span>子页面<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span></span><br><span class="line"><span class="comment">// home.vue：路由之间使用 router，当前路由使用 toute</span></span><br><span class="line"><span class="keyword">import</span> &#123;useRouter, useRoute, onBeforeRouteLeave&#125; <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span></span><br><span class="line"><span class="keyword">const</span> router = <span class="title function_">useRouter</span>()</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">toUser</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    router.<span class="title function_">push</span>(<span class="string">&#x27;user&#x27;</span>)</span><br><span class="line">    router.<span class="title function_">push</span>(&#123; <span class="attr">path</span>: <span class="string">&#x27;/user&#x27;</span>, <span class="attr">query</span>: &#123; <span class="attr">id</span>: <span class="number">1</span> &#125;)</span><br><span class="line">    router.<span class="title function_">push</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;user&#x27;</span>,  <span class="attr">params</span>: &#123; <span class="attr">name</span>: <span class="string">&#x27;Tom&#x27;</span> &#125;)</span><br><span class="line">    router.<span class="title function_">go</span>(<span class="number">1</span>) === router.<span class="title function_">forward</span>() </span><br><span class="line">    router.<span class="title function_">go</span>(-<span class="number">1</span>) === router.<span class="title function_">back</span>() </span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">onBeforeRouteLeave</span>(<span class="function">(<span class="params">to,<span class="keyword">from</span></span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;我离开啦&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">let</span> props = <span class="title function_">defineProps</span>([<span class="string">&quot;id&quot;</span>]);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(props, <span class="variable language_">this</span>.<span class="property">$route</span>);</span><br><span class="line"><span class="comment">// user.vue</span></span><br><span class="line"><span class="keyword">const</span> route = <span class="title function_">useRoute</span>()</span><br><span class="line"><span class="keyword">let</span> data = <span class="title function_">reactive</span>(&#123; <span class="attr">query</span>: route.<span class="property">query</span> / route.<span class="property">params</span> &#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> <span class="variable">vite</span>-plugin-pages：根据 pages 目录的文件自动生成路由</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> / ==&gt; src/pages/index.vue</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> /users ==&gt; src/pages/users/index.vue</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> /users/:id ==&gt; src/pages/users/[id].vue</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> /:user/son ==&gt; src/pages/[user]/son.vue</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> <span class="variable">vite</span>-plugin-vue-layouts：指定 pages 目录文件的路由</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  安装：npm i -D vite-plugin-pages vite-plugin-vue-layouts</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  main.js 集成：createApp(App).use(router).mount(&#x27;#app&#x27;)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  virtual:generated-layouts：虚拟模块</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">import</span> &#123; createRouter, createWebHashHistory &#125; <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; setupLayouts &#125; <span class="keyword">from</span> <span class="string">&#x27;virtual:generated-layouts&#x27;</span></span><br><span class="line"><span class="keyword">import</span> routes <span class="keyword">from</span> <span class="string">&#x27;virtual:generated-pages&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">const</span> router = <span class="title function_">createRouter</span>(&#123;</span><br><span class="line">    <span class="attr">history</span>: <span class="title function_">createWebHashHistory</span>(),</span><br><span class="line">    <span class="attr">routes</span>: routes / <span class="title function_">setupLayouts</span>(routes)</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// vite.config.ts</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Pages</span> <span class="keyword">from</span> <span class="string">&#x27;vite-plugin-pages&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Layouts</span> <span class="keyword">from</span> <span class="string">&#x27;vite-plugin-vue-layouts&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>(&#123;</span><br><span class="line">    <span class="attr">plugins</span>: [<span class="title class_">Pages</span>(), <span class="title class_">Layouts</span>()]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// .eslintrc.js：路径别名、虚拟模块等不是标准 ES6 而会报错</span></span><br><span class="line"><span class="attr">rules</span>: &#123; <span class="string">&#x27;import/no-unresolved&#x27;</span>: <span class="string">&#x27;off&#x27;</span> &#125;</span><br><span class="line"><span class="comment">// tsconfig.json：支持 ts 解析虚拟模块</span></span><br><span class="line"><span class="attr">compilerOptions</span>: &#123; </span><br><span class="line">    <span class="string">&#x27;types&#x27;</span>: [</span><br><span class="line">        <span class="string">&#x27;vite-plugin-pages/client&#x27;</span>, </span><br><span class="line">        <span class="string">&#x27;vite-plugin-vue-layouts/client&#x27;</span></span><br><span class="line">    ] </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// pages 文件配置：当前路由加载 src/layouts/users.vue</span></span><br><span class="line">&lt;route lang=<span class="string">&quot;yaml&quot;</span>&gt;</span><br><span class="line"><span class="attr">meta</span>:</span><br><span class="line">  <span class="attr">layout</span>: users</span><br><span class="line">&lt;/route&gt;</span><br></pre></td></tr></table></figure>


<h2 id="Pinia-状态"><a href="#Pinia-状态" class="headerlink" title="Pinia 状态"></a>Pinia 状态</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 取代 Vuex 的新一代官方状态管理器、npm i pinia -S</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  接口设计接近 Vuex5 提案，天生支持 typescript</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  store 支持多个、mutations 舍弃，actions 同/异步修改 state</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// main.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; createPinia, <span class="title class_">PiniaPlugin</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">createPinia</span>())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// store.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; defineStore &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; ref, computed &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">&#x27;@/router&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> storage <span class="keyword">from</span> <span class="string">&#x27;store&#x27;</span>;          <span class="comment">// 存储数据到本地浏览器</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">UaParser</span>, &#123; <span class="title class_">IResult</span> <span class="keyword">as</span> <span class="title class_">UaResult</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;ua-parser-js&#x27;</span>;</span><br><span class="line">interface <span class="title class_">UserInfo</span> &#123;</span><br><span class="line">    <span class="attr">id</span>: string;</span><br><span class="line">    <span class="attr">token</span>: string;</span><br><span class="line">    name?: string;</span><br><span class="line">    avatar?: string;</span><br><span class="line">    roles?: string[];</span><br><span class="line">&#125;</span><br><span class="line">interface <span class="title class_">UserState</span> &#123;</span><br><span class="line">    <span class="attr">count</span>: number;</span><br><span class="line">    <span class="attr">userInfo</span>: <span class="title class_">UserInfo</span>;</span><br><span class="line">    <span class="attr">ua</span>: <span class="title class_">UaResult</span>;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> defaultUserInfo = &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">token</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">avatar</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">roles</span>: []</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// export const useUserStore = defineStore(&#x27;User&#x27;, () =&gt; &#123; &#125;)</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useUserStore = <span class="title function_">defineStore</span>(<span class="string">&#x27;User&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">state</span>: (): <span class="function"><span class="params">UserState</span> =&gt;</span> (&#123;</span><br><span class="line">        <span class="attr">count</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">userInfo</span>: &#123; ...defaultUserInfo &#125;,</span><br><span class="line">        <span class="attr">ua</span>: <span class="keyword">new</span> <span class="title class_">UaParser</span>().<span class="title function_">getResult</span>()    <span class="comment">// 解析浏览器</span></span><br><span class="line">    &#125;),</span><br><span class="line">    <span class="attr">getters</span>: &#123;</span><br><span class="line">        <span class="attr">doubleCount</span>: <span class="function">(<span class="params">state</span>) =&gt;</span> state.<span class="property">count</span> * <span class="number">2</span>,</span><br><span class="line">        <span class="title function_">increment</span>(<span class="params">num</span>) &#123; <span class="variable language_">this</span>.<span class="property">count</span> += num &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">actions</span>: &#123;</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">getUserInfo</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> userID = storage.<span class="title function_">get</span>(<span class="string">&#x27;USER_ID&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (userID) <span class="keyword">return</span></span><br><span class="line">            <span class="comment">// 异步调用查询接口</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">login</span>(<span class="params">payload: UserInfo</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">userInfo</span> = payload;</span><br><span class="line">            storage.<span class="title function_">set</span>(<span class="string">&#x27;USER_ID&#x27;</span>, payload.<span class="property">id</span>);</span><br><span class="line">            storage.<span class="title function_">set</span>(<span class="string">&#x27;ACCESS_TOKEN&#x27;</span>, payload.<span class="property">token</span>);</span><br><span class="line">            router.<span class="title function_">push</span>(&#123; <span class="attr">path</span>: <span class="string">&#x27;/&#x27;</span> &#125;);</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">logout</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">userInfo</span> = &#123; ...defaultUserInfo &#125;;</span><br><span class="line">            router.<span class="title function_">push</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;Login&#x27;</span> &#125;);</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">verification</span>(<span class="params">token: string</span>) &#123;</span><br><span class="line">            <span class="comment">// 调用 token 验证接口</span></span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(token);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件调用</span></span><br><span class="line"><span class="keyword">import</span> &#123; useUserStore &#125; <span class="keyword">from</span> <span class="string">&#x27;@/store&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; storeToRefs &#125; <span class="keyword">from</span> <span class="string">&#x27;pinia&#x27;</span></span><br><span class="line"><span class="keyword">const</span> userStore = <span class="title function_">useUserStore</span>()</span><br><span class="line"><span class="keyword">const</span> &#123; count &#125; = <span class="title function_">storeToRefs</span>(userStore)</span><br><span class="line"><span class="keyword">const</span> &#123; count &#125; = userStore   <span class="comment">// 会丢失数据响应式的错误写法</span></span><br><span class="line">userStore.<span class="property">count</span> = <span class="number">10</span>          <span class="comment">// 直接修改：不推荐</span></span><br><span class="line">userStore.<span class="title function_">increment</span>(<span class="number">1</span>)        <span class="comment">// 推荐修改</span></span><br><span class="line">userStore.$patch(<span class="function"><span class="params">state</span> =&gt;</span> &#123;   <span class="comment">// 批量修改</span></span><br><span class="line">    state.<span class="property">count</span>++</span><br><span class="line">&#125;)</span><br><span class="line">userStore.$reset()            <span class="comment">// 重置 state</span></span><br></pre></td></tr></table></figure>


<h2 id="axios-通信"><a href="#axios-通信" class="headerlink" title="axios 通信"></a>axios 通信</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js：全局方式一</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&quot;axios&quot;</span>;</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">createApp</span>(<span class="title class_">App</span>)</span><br><span class="line">app.<span class="property">config</span>.<span class="property">globalProperties</span>.<span class="property">$axios</span> = axios;</span><br><span class="line"><span class="comment">// 组件引用</span></span><br><span class="line"><span class="keyword">import</span> &#123; getCurrentInstance &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">const</span> &#123; proxy &#125; = <span class="title function_">getCurrentInstance</span>()</span><br><span class="line">proxy.$axios(&#123; &#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// main.js：全局方式二</span></span><br><span class="line">app.<span class="title function_">provide</span>(<span class="string">&#x27;$axios&#x27;</span>, axios)</span><br><span class="line"><span class="comment">// 组件引用</span></span><br><span class="line"><span class="keyword">import</span> &#123; inject &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">const</span> $axios = <span class="title function_">inject</span>(<span class="string">&#x27;$axios&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// axios 封装：npm i axios element-plus -D</span></span><br><span class="line"><span class="keyword">import</span> axios, &#123; <span class="title class_">AxiosInstance</span>, <span class="title class_">AxiosError</span>, <span class="title class_">AxiosRequestConfig</span>, </span><br><span class="line"><span class="title class_">AxiosResponse</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">ElMessage</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;element-plus&#x27;</span></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="variable constant_">VITE_APP_BASE_URL</span> &#125; = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">env</span>;</span><br><span class="line">interface <span class="title class_">ResData</span>&lt;T = <span class="literal">null</span>&gt; &#123;</span><br><span class="line">    <span class="attr">code</span>: number;</span><br><span class="line">    <span class="attr">message</span>: string;</span><br><span class="line">    data?: T;</span><br><span class="line">&#125;</span><br><span class="line">enum <span class="title class_">RequestEnums</span> &#123;</span><br><span class="line">    <span class="variable constant_">TIMEOUT</span> = <span class="number">20000</span>,    <span class="comment">// 请求超时</span></span><br><span class="line">    <span class="variable constant_">OVERDUE</span> = <span class="number">600</span>,      <span class="comment">// 登录失效</span></span><br><span class="line">    <span class="variable constant_">FAIL</span> = <span class="number">999</span>,         <span class="comment">// 请求失败</span></span><br><span class="line">    <span class="variable constant_">SUCCESS</span> = <span class="number">200</span>       <span class="comment">// 请求成功</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> config = &#123;</span><br><span class="line">    <span class="attr">baseURL</span>: <span class="variable constant_">VITE_APP_BASE_URL</span> <span class="keyword">as</span> string,,</span><br><span class="line">    <span class="attr">headers</span>: &#123; <span class="attr">timestamp</span>: <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>() &#125;,</span><br><span class="line">    <span class="attr">timeout</span>: <span class="title class_">RequestEnums</span>.<span class="property">TIMEOUT</span> <span class="keyword">as</span> number,</span><br><span class="line">    <span class="comment">// http.get/request 代理服务，keepAlive 保持套接字</span></span><br><span class="line">    <span class="attr">httpAgent</span>: <span class="keyword">new</span> http.<span class="title class_">Agent</span>(&#123; <span class="attr">keepAlive</span>: <span class="literal">true</span> &#125;),</span><br><span class="line">    <span class="attr">httpsAgent</span>: <span class="keyword">new</span> https.<span class="title class_">Agent</span>(&#123; <span class="attr">keepAlive</span>: <span class="literal">true</span> &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">HttpRequest</span> &#123;</span><br><span class="line">    protected <span class="attr">service</span>: <span class="title class_">AxiosInstance</span>;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">constructor</span>(<span class="params">config: AxiosRequestConfig</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">service</span> = axios.<span class="title function_">create</span>(config);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">interceptorsRequest</span>();</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">interceptorsResponse</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 拦截器</span></span><br><span class="line">    protected <span class="title function_">interceptorsRequest</span>(): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">service</span>.<span class="property">interceptors</span>.<span class="property">request</span>.<span class="title function_">use</span>(</span><br><span class="line">            <span class="function">(<span class="params">config: AxiosRequestConfig</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="title class_">HttpRequest</span>.<span class="title function_">setAuthHeader</span>(config);</span><br><span class="line">                <span class="keyword">return</span> config</span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="function">(<span class="params">error: any</span>) =&gt;</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error)</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected <span class="title function_">interceptorsResponse</span>(): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">service</span>.<span class="property">interceptors</span>.<span class="property">response</span>.<span class="title function_">use</span>(</span><br><span class="line">            <span class="function">(<span class="params">response: AxiosResponse</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">const</span> &#123;data, config&#125; = response;</span><br><span class="line">                <span class="keyword">if</span> (data.<span class="property">code</span> === <span class="title class_">RequestEnums</span>.<span class="property">OVERDUE</span>) &#123;</span><br><span class="line">                    <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(<span class="string">&#x27;token&#x27;</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(data);</span><br><span class="line">                &#125;</span><br><span class="line">                 <span class="keyword">if</span> (data.<span class="property">code</span> !== <span class="title class_">RequestEnums</span>.<span class="property">SUCCESS</span>) &#123;</span><br><span class="line">                     <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(data);</span><br><span class="line">                     <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(data)</span><br><span class="line">                 &#125;</span><br><span class="line">                 <span class="keyword">return</span> data;</span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="function">(<span class="params">error: AxiosError</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (!<span class="variable language_">window</span>.<span class="property">navigator</span>.<span class="property">onLine</span>) &#123;</span><br><span class="line">                    <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(<span class="string">&#x27;网络连接失败&#x27;</span>);</span><br><span class="line">                    <span class="keyword">return</span></span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">const</span> &#123; response &#125; = error;</span><br><span class="line">                <span class="keyword">if</span> (response) &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="title function_">handleCode</span>(response.<span class="property">status</span>)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">handleCode</span>(<span class="attr">code</span>: number): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="keyword">switch</span> (code) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">401</span>:</span><br><span class="line">                <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(<span class="string">&#x27;登录失败，请重新登录&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(<span class="string">`请求失败(<span class="subst">$&#123;code&#125;</span>)!`</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected <span class="keyword">static</span> <span class="title function_">setAuthHeader</span>(<span class="attr">config</span>: <span class="title class_">AxiosRequestConfig</span>): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="comment">// 身份认证、主机地址</span></span><br><span class="line">        <span class="keyword">const</span> <span class="variable constant_">TOKEN</span> = <span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">getItem</span>(<span class="variable constant_">TOKEN</span>)</span><br><span class="line">        <span class="variable constant_">TOKEN</span> &amp;&amp; config.<span class="property">headers</span>[<span class="string">&#x27;authorization&#x27;</span>] = <span class="variable constant_">TOKEN</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">window</span>.<span class="property">returnCitySN</span>) &#123;</span><br><span class="line">            config.<span class="property">headers</span>[<span class="string">&#x27;cip&#x27;</span>] = <span class="variable language_">window</span>.<span class="property">returnCitySN</span>.<span class="property">cip</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 单例模式：不是实例则实例化后返回</span></span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">getInstance</span>(config): <span class="title class_">HttpRequest</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title class_">HttpRequest</span>.<span class="property">instance</span>) &#123;</span><br><span class="line">            <span class="title class_">HttpRequest</span>.<span class="property">instance</span> = <span class="keyword">new</span> <span class="title class_">HttpRequest</span>(config)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">HttpRequest</span>.<span class="property">instance</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    get&lt;T&gt;(<span class="attr">url</span>: string, params?: object): <span class="title class_">Promise</span>&lt;<span class="title class_">ResData</span>&lt;T&gt;&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">service</span>.<span class="title function_">get</span>(url, &#123; params &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    post&lt;T&gt;(<span class="attr">url</span>: string, params?: object): <span class="title class_">Promise</span>&lt;<span class="title class_">ResData</span>&lt;T&gt;&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">service</span>.<span class="title function_">post</span>(url, params);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">delete</span>&lt;T&gt;(<span class="attr">url</span>: string, params?: object): <span class="title class_">Promise</span>&lt;<span class="title class_">ResData</span>&lt;T&gt;&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">service</span>.<span class="title function_">delete</span>(url, &#123; params &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">HttpRequest</span>.<span class="title function_">getInstance</span>(config);</span><br></pre></td></tr></table></figure>


<h1 id="二、版本优化"><a href="#二、版本优化" class="headerlink" title="二、版本优化"></a>二、版本优化</h1><h2 id="功能优化"><a href="#功能优化" class="headerlink" title="功能优化"></a>功能优化</h2><blockquote>
<p>废弃了过滤器功能、$on&#x2F;$emit&#x2F;$off&#x2F;$once 等实例方法、支持多根节点组件和 TypeScript、使用函数的 Composition API (响应式 ref&#x2F;生命周期 onMounted &#x2F;依赖注入 provide 等一系列接口的集合) 取代了声明变量的选项式 API、通过 Proxy + Reflect 取代 Object.definepeoperty() 实现的响应式对象可以直接操作而不需要每次遍历对象属性。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>&#123;&#123; counter &#125;&#125;<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;incrCounter&quot;</span>&gt;</span>Click Me<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">// script-setup 模式提供了四个全局编译器宏，使用时无需 import</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">// defineProps、defineEmits、defineExpose、withDefaults</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> props = <span class="title function_">defineProps</span>(&#123; </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">name</span>: <span class="title class_">String</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">age</span>:&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">type</span>: <span class="title class_">Number</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">require</span>: <span class="literal">true</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">default</span>: <span class="number">1</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;挂载后&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">// Composition 组合式：内部会将多个标签包含到 Fragment，有利于代码管理和类型推导。</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">name</span>: <span class="string">&quot;demo&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title function_">setup</span>(<span class="params">props, context</span>) &#123;    <span class="comment">// 创建实例前</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">import</span> &#123; </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            createApp,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            reactive,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            ref,               <span class="comment">// 创建响应式的数据对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            toRefs,            <span class="comment">// 转换为单一响应式对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            isRef,             <span class="comment">// 判断某值是否引用类型</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            watch,             <span class="comment">// 创建 watch 监听</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            computed,          <span class="comment">// 创建计算属性</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            onMounted,         <span class="comment">// 生命周期钩子</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            onUpdated,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            onUnmounted</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">let</span> counter = <span class="title function_">ref</span>(<span class="number">0</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">let</span> incrCounter = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            counter.<span class="property">value</span> += <span class="number">1</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">let</span> lineNo = <span class="title function_">computed</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="keyword">return</span> counter + <span class="string">&#x27;0&#x27;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="comment">// 监听多个：[counter, lineNo]</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">watch</span>(counter, <span class="function">(<span class="params">newVal, oldVal</span>) =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;监听数据&#x27;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;, &#123; <span class="attr">immediate</span>: <span class="literal">true</span>&#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">let</span> person = <span class="title function_">reactive</span>(&#123; <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>, <span class="attr">age</span>: <span class="number">10</span> &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">watch</span>(<span class="function">()=&gt;</span> person.<span class="property">name</span>, <span class="function">(<span class="params">newVal, oldVal</span>) =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;监听属性 name&#x27;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;,&#123; <span class="attr">immediate</span>: <span class="literal">true</span>, <span class="attr">deep</span>: <span class="literal">true</span>&#125;) </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">watchEffect</span>(<span class="function">(<span class="params">onInvalidate</span>) =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="keyword">const</span> timer = <span class="built_in">setInterval</span>(<span class="function">()=&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">               </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            &#125;, <span class="number">1000</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="title function_">onInvalidate</span>(<span class="function">() =&gt;</span> <span class="built_in">clearInterval</span>(timer))</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onBeforeMount</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;挂载前&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;挂载后&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onBeforeUpdate</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;更新前&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onUpdated</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;更新后&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onBeforeUnmount</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;卸载前&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">onUnmounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;卸载后&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">return</span> &#123; counter, lineNo, incrCounter &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">// Options 选项式：适用于简单项目</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title function_">data</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">return</span> &#123; <span class="attr">counter</span>: <span class="number">0</span> &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">methods</span>: &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">incrCounter</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">            <span class="variable language_">this</span>.<span class="property">counter</span> += <span class="number">1</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// v-model：父子组件，sync 修饰符已废弃，支持绑定多个</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">child</span> <span class="attr">v-model</span>=<span class="string">&quot;name&quot;</span> <span class="attr">v-model:email</span>=<span class="string">&quot;email&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="keyword">const</span> name = ref&lt;string&gt;(<span class="string">&#x27;张三丰&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> email = ref&lt;string&gt;(<span class="string">&#x27;66@qq.com&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> emits = defineEmits&lt;&#123;</span><br><span class="line">    (<span class="attr">e</span>: <span class="string">&#x27;update:modelValue&#x27;</span>, <span class="attr">value</span>: string): <span class="keyword">void</span></span><br><span class="line">    (<span class="attr">e</span>: <span class="string">&#x27;update:email&#x27;</span>, <span class="attr">value</span>: string): <span class="keyword">void</span></span><br><span class="line">&#125;&gt;()</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">updateName</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="title function_">emits</span>(<span class="string">&#x27;update:modelValue&#x27;</span>, <span class="string">&#x27;李四&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">updateEmail</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="title function_">emits</span>(<span class="string">&#x27;update:email&#x27;</span>, <span class="string">&#x27;12@qq.com&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// watch：支持传入一个数组同时监听多个数据</span></span><br><span class="line"><span class="keyword">const</span> name = ref&lt;string&gt;(<span class="string">&#x27;张三&#x27;</span>)</span><br><span class="line"><span class="title function_">watch</span>(name, <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123; </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;基础数据类型&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">interface <span class="title class_">UserInfo</span> &#123; <span class="attr">name</span>: string <span class="attr">age</span>: number &#125;</span><br><span class="line"><span class="keyword">const</span> userInfo = reactive&lt;<span class="title class_">UserInfo</span>&gt;(&#123; <span class="attr">name</span>: <span class="string">&#x27;张三&#x27;</span>, <span class="attr">age</span>: <span class="number">10</span> &#125;)</span><br><span class="line"><span class="title function_">watch</span>(userInfo, <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123; </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;监听整个对象&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title function_">watch</span>(<span class="function">() =&gt;</span> userInfo.<span class="property">name</span>,  <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;监听对象属性&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="title function_">watch</span>([name, <span class="function">()=&gt;</span>userInfo.<span class="property">age</span>], <span class="function">(<span class="params">[newN, newA], [oldN, oldA]</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;同时监听 name、userInfo.age 属性&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// watchEffect：传入的函数参数会立即执行，并且在依赖发生改变时重新运行</span></span><br><span class="line"><span class="keyword">const</span> age = ref&lt;number&gt;(<span class="number">18</span>)</span><br><span class="line"><span class="title function_">watchEffect</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;name.value&#125;</span>：<span class="subst">$&#123;userInfo.age.value&#125;</span>`</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    name.<span class="property">value</span> = <span class="string">&#x27;李四&#x27;</span></span><br><span class="line">&#125;, <span class="number">3000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// $attrs：包含父组件 props 和自定义事件之外的所有属性，$listenners 被移除</span></span><br><span class="line">&lt;child name=<span class="string">&quot;父组件&quot;</span> @confirm=<span class="string">&quot;getData&quot;</span> /&gt;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">grandson</span> <span class="attr">v-bind</span>=<span class="string">&quot;attrs&quot;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">grandson</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">inheritAttrs</span>: <span class="literal">false</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> props = <span class="title function_">defineProps</span>([<span class="string">&#x27;name&#x27;</span>])</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> attrs = <span class="title function_">useAttrs</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;父组件的属性和自定义事件&#x27;</span>, attrs)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// v-bind 实现组件属性和事件透传 (向下继续传递)</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">child</span> <span class="attr">closeable</span> <span class="attr">:title</span>=<span class="string">&quot;title&quot;</span> @<span class="attr">close</span>=<span class="string">&quot;onClose&quot;</span> /&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ref 访问子组件的属性和方法，但子组件必须使用 defineExpose 暴露</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">child</span> <span class="attr">ref</span>=<span class="string">&quot;childRef&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="keyword">const</span> childRef = <span class="title function_">ref</span>()</span><br><span class="line"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    childRef.<span class="property">value</span>.<span class="title function_">getData</span>()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; defineExpose &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">getData</span> = (<span class="params"></span>) =&gt; &#123;  &#125;</span><br><span class="line"><span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&#x27;张三&#x27;</span>)</span><br><span class="line"><span class="title function_">defineExpose</span>(&#123; getData, name &#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 自定义全局变量：main.js</span></span><br><span class="line"><span class="title function_">createApp</span>(<span class="title class_">App</span>).<span class="property">config</span>.<span class="property">globalProperties</span>.<span class="property">$api</span> = axios;</span><br><span class="line"><span class="title class_">Vue</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">$api</span> = axios;    <span class="comment">// vue2 写法</span></span><br><span class="line"><span class="comment">// 组件使用：setup 为组合 API 时的编译语法糖，一个返回对象或渲染函数的函数。</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; ref, onMounted, getCurrentInstance &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">const</span> instance = &lt;any&gt;<span class="title function_">getCurrentInstance</span>();</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">const</span> &#123;$api&#125; = instance.<span class="property">appContext</span>.<span class="property">config</span>.<span class="property">globalProperties</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">// 全局异常处理：main.ts 可集成错误追踪服务 Sentry、Bugsnag</span></span><br><span class="line"><span class="language-xml">app.config.errorHandler = (err, vm, info) =&gt; &#123;</span></span><br><span class="line"><span class="language-xml">    console.log(&#x27;[全局异常]&#x27;, err, vm, info)</span></span><br><span class="line"><span class="language-xml">&#125;</span></span><br></pre></td></tr></table></figure>


<h2 id="响应式开发"><a href="#响应式开发" class="headerlink" title="响应式开发"></a>响应式开发</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 创建响应式对象 API</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> ref：将任意数据转为响应式对象，对象值更新时视图会自动更新 (复制)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> toRef：将对象属性转为响应式，更新时修改原对象但视图不更新 (引用)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> toRefs：遍历对象属性并调用 toRef，用于将整个对象转化成响应式</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> reactive：将一个对象或数组转换为响应式，注意不可传入原始数据</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> defineComponent：用于编辑器在 ts 环境的类型推导而进行语法提示</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> isRef、isReactive、isReadonly、isProxy：判定数据是否响应式</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> customRef：自定义一个 ref 并对依赖项跟踪和更新触发进行显式控制</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, ref, reactive, onMounted &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;HomeView&#x27;</span>,</span><br><span class="line">    setup () &#123;</span><br><span class="line">        <span class="comment">// dom 元素：&lt;span ref=&quot;span&quot;&gt;名称&lt;/span&gt;</span></span><br><span class="line">        <span class="keyword">let</span> span = <span class="title function_">ref</span>(<span class="literal">null</span>);</span><br><span class="line">        <span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            span.<span class="property">value</span>.<span class="property">style</span>.<span class="property">color</span> = <span class="string">&quot;red&quot;</span>;</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 响应式变量</span></span><br><span class="line">        <span class="keyword">let</span> msg = <span class="title function_">ref</span>(<span class="string">&#x27;msg&#x27;</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isRef</span>(msg))  <span class="comment">// true  </span></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">changeMsg</span> () &#123;</span><br><span class="line">            msg.<span class="property">value</span>.<span class="property">msg</span> = <span class="string">&#x27;new msg&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> person = &#123; <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>, <span class="attr">age</span>: <span class="number">10</span> &#125;</span><br><span class="line">        <span class="keyword">let</span> _msg = <span class="title function_">toRef</span>(person, <span class="string">&#x27;name&#x27;</span>)</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">_changeMsg</span> () &#123;</span><br><span class="line">            _msg.<span class="property">value</span>.<span class="property">msg</span> = <span class="string">&#x27;new msg&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> info = <span class="title function_">reactive</span>(&#123; <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>, <span class="attr">age</span>: <span class="number">10</span> &#125;)</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">changeAge</span> () &#123;</span><br><span class="line">            info.<span class="property">age</span>++</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">watch</span>(msg, <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(newValue, oldValue)</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="comment">// 自定义 ref</span></span><br><span class="line">        <span class="keyword">const</span> text = <span class="title function_">useDebouncedRef</span>(<span class="string">&#x27;hello&#x27;</span>);</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            msg,</span><br><span class="line">            changeMsg,</span><br><span class="line">            ...<span class="title function_">toRefs</span>(info),</span><br><span class="line">            changeAge</span><br><span class="line">            nameRef</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; customRef &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useDebouncedRef</span> (value, delay = <span class="number">200</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> timeout</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">customRef</span>(<span class="function">(<span class="params">track, trigger</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            get () &#123;</span><br><span class="line">                <span class="title function_">track</span>()</span><br><span class="line">                <span class="keyword">return</span> value</span><br><span class="line">            &#125;,</span><br><span class="line">            set (newValue) &#123;</span><br><span class="line">                <span class="built_in">clearTimeout</span>(timeout)</span><br><span class="line">                timeout = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                    value = newValue</span><br><span class="line">                    <span class="title function_">trigger</span>()</span><br><span class="line">                &#125;, delay)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 响应式原理：Proxy + Reflect 监听对象而非属性而且可直接操作。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Proxy：拦截对象的读写等操作并在前后注入自定义逻辑的代理器。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Reflect：提供了一组对象操作方法的 window 内置对象。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">name</span>: <span class="string">&quot;Jack&quot;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;</span><br><span class="line"><span class="keyword">let</span> objProxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(obj, &#123;</span><br><span class="line">    <span class="title function_">has</span>(<span class="params">target, name</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;get 属性判断&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">has</span>(target, name)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">get</span>(<span class="params">target, prop</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;get 属性读取&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">get</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">set</span>(<span class="params">target, prop, newValue</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;set 属性设置&#x27;</span>)</span><br><span class="line">        <span class="title class_">Reflect</span>.<span class="title function_">set</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">defineProperty</span>(<span class="params">target, prop, discriptor</span>) &#123; </span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;拦截 Object.defineProperty&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">defineProperty</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">deleteProperty</span>(<span class="params">target, prop</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;拦截 delete&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">deleteProperty</span>(target, prop)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line">obj.<span class="property">age</span> = <span class="number">30</span>;</span><br><span class="line"><span class="keyword">delete</span> obj.<span class="property">age</span>;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(obj, <span class="string">&#x27;name&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">writable</span>: <span class="literal">true</span>,        <span class="comment">// 可修改</span></span><br><span class="line">    <span class="attr">enumerable</span>: <span class="literal">true</span>,      <span class="comment">// 可遍历</span></span><br><span class="line">    <span class="attr">configurable</span>: <span class="literal">true</span>,    <span class="comment">// 可删</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">sum</span> = (<span class="params">a, b</span>) =&gt; &#123; <span class="keyword">return</span> a + b &#125;</span><br><span class="line"><span class="keyword">let</span> fnProxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(sum, &#123;</span><br><span class="line">    <span class="title function_">apply</span>(<span class="params">targetFn, thisArg, ...args</span>) &#123;  <span class="comment">// 拦截函数调用</span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;apply&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">apply</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title function_">sum</span>(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// reactive：创建响应式对象</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reactive</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> handler = &#123;</span><br><span class="line">        <span class="attr">deps</span>: <span class="keyword">new</span> <span class="title class_">Set</span>(),</span><br><span class="line">        <span class="title function_">get</span>(<span class="params">target, key, receiver</span>)&#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">deps</span>.<span class="title function_">add</span>(<span class="title function_">track</span>(target, key))</span><br><span class="line">            <span class="keyword">const</span> value = <span class="title class_">Reflect</span>.<span class="title function_">get</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">typeof</span> value === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">reactive</span>(value)</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> value</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">set</span>(<span class="params">target, key, val, receiver</span>)&#123;</span><br><span class="line">            <span class="title function_">trigger</span>(<span class="variable language_">this</span>.<span class="property">deps</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">set</span>(...<span class="variable language_">arguments</span>)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Proxy</span>(obj, handler)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">track</span>(<span class="params">target, key</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">()=&gt;</span>&#123; <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`属性：<span class="subst">$&#123;key&#125;</span>`</span>)&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">deps</span>)&#123;    <span class="comment">// 响应式触发</span></span><br><span class="line">    <span class="keyword">if</span> (!deps) <span class="keyword">return</span></span><br><span class="line">    deps.<span class="title function_">forEach</span>(<span class="function"><span class="params">effect</span> =&gt;</span> &#123; <span class="title function_">effect</span>() &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ref：将普通值包装为一个响应式对象</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">ref</span>(<span class="params">value</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RefImpl</span>(value);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">RefImpl</span> &#123;</span><br><span class="line">    private _value = <span class="literal">null</span>;</span><br><span class="line">    private __v_isRef = <span class="literal">true</span>;</span><br><span class="line">    private dep = <span class="literal">null</span>;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">public val</span>)&#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_value</span> = <span class="title function_">isObject</span>(val) ? <span class="title function_">reactive</span>(val): val</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">value</span>()&#123;</span><br><span class="line">        <span class="keyword">if</span> (activeEffect) &#123;</span><br><span class="line">            <span class="title function_">trackEffects</span>(<span class="variable language_">this</span>.<span class="property">dep</span> ||(<span class="variable language_">this</span>.<span class="property">dep</span> = <span class="keyword">new</span> <span class="title class_">Set</span>()))</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_value</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> <span class="title function_">value</span>(<span class="params">newVal</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span> (newVal !== <span class="variable language_">this</span>.<span class="property">val</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_value</span> = <span class="title function_">toReactive</span>(newVal)</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">val</span> = newVal</span><br><span class="line">            <span class="title function_">trigger</span>(<span class="variable language_">this</span>.<span class="property">dep</span>)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// toRef：解析对象而对单个属性实现响应式</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">toRef</span>(<span class="params">object, key</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ObjectRefImpl</span>(object, key)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">toRefs</span>(<span class="params">object</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> ret = object <span class="keyword">instanceof</span> <span class="title class_">Array</span> ? </span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Array</span>(object.<span class="property">length</span>) : &#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> object) &#123;</span><br><span class="line">        ret[key] = <span class="title function_">toRef</span>(object, key)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ret</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ObjectRefImpl</span>&#123;</span><br><span class="line">    private __v_isRef = <span class="literal">true</span>;</span><br><span class="line">    private _value = <span class="literal">null</span>;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">public object, public key</span>)&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">value</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">object</span>[<span class="variable language_">this</span>.<span class="property">key</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> <span class="title function_">value</span>(<span class="params">newValue</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">object</span>[<span class="variable language_">this</span>.<span class="property">key</span>] = newValue</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="Hooks-工具"><a href="#Hooks-工具" class="headerlink" title="Hooks 工具"></a>Hooks 工具</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">useMouse</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> state = <span class="title function_">reactive</span>(&#123; <span class="attr">x</span>: <span class="number">0</span>, <span class="attr">y</span>: <span class="number">0</span> &#125;)</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">update</span> = e =&gt; &#123;</span><br><span class="line">        state.<span class="property">x</span> = e.<span class="property">pageX</span></span><br><span class="line">        state.<span class="property">y</span> = e.<span class="property">pageY</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;mousemove&#x27;</span>, update)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="title function_">onUnmounted</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">window</span>.<span class="title function_">removeEventListener</span>(<span class="string">&#x27;mousemove&#x27;</span>, update)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">toRefs</span>(state)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> VueUse 工具集：类似 React Hooks、npm i <span class="doctag">@vueuse</span>/core</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Animation：包含易于使用的过渡、超时和计时功能</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Browser：可用于不同的屏幕控制、剪贴板、偏好等</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Component：提供了不同组件方法的简写</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Formatters：提供响应时间格式化功能</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Sensors：用来监听不同的DOM事件、输入事件和网络事件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> State：管理用户状态（全局、本地存储、会话存储）</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Utility：不同的实用函数，如 getter、条件、引用同步等</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Watch：高级观察器，如可暂停的、退避的观察器和条件观察器</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> Misc：不同类型的事件、WebSockets、WebWorker 的功能</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">import</span> &#123; useMouse, useCounter &#125; <span class="keyword">from</span> <span class="string">&#x27;@vueuse/core&#x27;</span>;</span><br><span class="line"><span class="comment">// useMouse：鼠标位置</span></span><br><span class="line"><span class="keyword">const</span> &#123; x, y &#125; = <span class="title function_">useMouse</span>(&#123;</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&#x27;page&#x27;</span>,</span><br><span class="line">    <span class="attr">touch</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">resetOnTouchEnds</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">initialValue</span>: &#123; <span class="attr">x</span>: <span class="number">100</span>, <span class="attr">y</span>: <span class="number">200</span> &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 基本计数器</span></span><br><span class="line"><span class="keyword">const</span> &#123; count, inc, dec, set, reset &#125; = <span class="title function_">useCounter</span>(<span class="number">1</span>)</span><br><span class="line"><span class="comment">// 响应式本地化存储</span></span><br><span class="line"><span class="keyword">const</span> count = <span class="title function_">useStorage</span>(<span class="string">&#x27;my-count&#x27;</span>, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">const</span> state = <span class="title function_">useLocalStorage</span>(<span class="string">&#x27;my-lol&#x27;</span>, &#123; <span class="attr">name</span>: <span class="string">&#x27;泰达&#x27;</span>, <span class="attr">type</span>: <span class="string">&#x27;战士&#x27;</span> &#125;)</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">handleReset</span> = (<span class="params"></span>) =&gt; &#123; state.<span class="property">value</span> = <span class="literal">null</span> &#125;</span><br><span class="line"><span class="comment">// 防抖</span></span><br><span class="line"><span class="keyword">const</span> counter = <span class="title function_">ref</span>(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">const</span> debouncedFn = <span class="title function_">useDebounceFn</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    counter.<span class="property">value</span> += <span class="number">1</span></span><br><span class="line">&#125;, <span class="number">1000</span>, &#123; <span class="attr">maxWait</span>: <span class="number">5000</span> &#125;)</span><br><span class="line"><span class="comment">// 剪切</span></span><br><span class="line"><span class="keyword">const</span> source = <span class="title function_">ref</span>(<span class="string">&#x27;Hello&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> &#123; text, copy, copied, isSupported &#125; = <span class="title function_">useClipboard</span>(&#123; source &#125;)</span><br></pre></td></tr></table></figure>

  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/***</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> Hooks 自定义封装</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> useRequest：统一管理网络请求的相关状态 (无需重复处理 loading、err)。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> useEventBus：组件卸载时自动取消当前监听事件 (无需重复 onUnmounted)。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> useModel：多个组件共享 hook 状态，一种跨组件共享数据的方案。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> useReducer：hook 实现简易 redux，useModel 实现全局 store。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> useDebounce、useThrottle：去抖和节流，对比 hook 代码与常规代码。</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useRequest</span>(<span class="params">api</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> loading = <span class="title function_">ref</span>(<span class="literal">false</span>)</span><br><span class="line">    <span class="keyword">const</span> result = <span class="title function_">ref</span>(<span class="literal">null</span>)</span><br><span class="line">    <span class="keyword">const</span> error = <span class="title function_">ref</span>(<span class="literal">null</span>)</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">fetchResource</span> = (<span class="params">params</span>) =&gt; &#123;</span><br><span class="line">        loading.<span class="property">value</span> = <span class="literal">true</span></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">api</span>(params).<span class="title function_">then</span>(<span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">            result.<span class="property">value</span> = data</span><br><span class="line">        &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123;</span><br><span class="line">            error.<span class="property">value</span> = e</span><br><span class="line">        &#125;).<span class="title function_">finally</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            loading.<span class="property">value</span> = <span class="literal">false</span></span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123; loading, error, result, fetchResource &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">useBook</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123;loading, error, result, fetchResource&#125; = <span class="title function_">useRequest</span>(<span class="function">()=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">resolve</span>(&#123; <span class="attr">code</span>: <span class="number">200</span>, <span class="attr">data</span>: <span class="literal">true</span> &#125;)</span><br><span class="line">            &#125;, <span class="number">1000</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123; <span class="title function_">fetchResource</span>(&#123;<span class="attr">page</span>: <span class="number">1</span>&#125;) &#125;)</span><br><span class="line">    <span class="keyword">return</span> &#123; loading, error, <span class="attr">list</span>: result&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> bus = <span class="keyword">new</span> <span class="title class_">EventBus</span>()  <span class="comment">// 事件总线，全局单例</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">useEventBus</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> instance = &#123;</span><br><span class="line">        <span class="attr">eventMap</span>: <span class="keyword">new</span> <span class="title class_">Map</span>(),</span><br><span class="line">        <span class="attr">on</span>: bus.<span class="property">on</span>,</span><br><span class="line">        <span class="attr">once</span>: bus.<span class="property">once</span>,</span><br><span class="line">        <span class="title function_">clear</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">eventMap</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">list, key</span>) =&gt;</span> &#123;</span><br><span class="line">                list.<span class="title function_">forEach</span>(<span class="function"><span class="params">cb</span> =&gt;</span> &#123;</span><br><span class="line">                    bus.<span class="title function_">off</span>(key, cb)</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;)</span><br><span class="line">            eventMap.<span class="title function_">clear</span>()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> eventMap = <span class="keyword">new</span> <span class="title class_">Map</span>()</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">on</span> = (<span class="params">key, cb</span>) =&gt; &#123;</span><br><span class="line">        instance.<span class="title function_">on</span>(key, cb)</span><br><span class="line">        bus.<span class="title function_">on</span>(key, cb)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">once</span> = (<span class="params">key, cb</span>) =&gt; &#123;</span><br><span class="line">        instance.<span class="title function_">once</span>(key, cb)</span><br><span class="line">        bus.<span class="title function_">once</span>(key, cb)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">onUnmounted</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        instance.<span class="title function_">clear</span>()</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        on,</span><br><span class="line">        once,</span><br><span class="line">        <span class="attr">off</span>: bus.<span class="property">off</span>.<span class="title function_">bind</span>(bus),</span><br><span class="line">        <span class="attr">emit</span>: bus.<span class="property">emit</span>.<span class="title function_">bind</span>(bus)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> map = <span class="keyword">new</span> <span class="title class_">WeakMap</span>()</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useModel</span>(<span class="params">hook</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!map.<span class="title function_">get</span>(hook)) &#123;</span><br><span class="line">        <span class="keyword">let</span> ans = <span class="title function_">hook</span>()</span><br><span class="line">        map.<span class="title function_">set</span>(hook, ans)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> map.<span class="title function_">get</span>(hook)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Counter</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> count = <span class="title function_">ref</span>(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">decrement</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        count.<span class="property">value</span>--</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">increment</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        count.<span class="property">value</span>++</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;count, decrement, increment&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">useCounter</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">useModel</span>(<span class="title class_">Counter</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 多组件调用</span></span><br><span class="line"><span class="keyword">const</span> &#123;count, decrement, increment&#125; = <span class="title function_">useCounter</span>()</span><br><span class="line"><span class="keyword">const</span> &#123;count, decrement, increment&#125; = <span class="title function_">useCounter</span>()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123;ref&#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useReducer</span>(<span class="params">reducer, initialState = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> state = <span class="title function_">ref</span>(initialState)</span><br><span class="line">    <span class="comment">// action 约定格式为 &#123;type:string, payload: any&#125;</span></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">dispatch</span> = (<span class="params">action</span>) =&gt; &#123;</span><br><span class="line">        state.<span class="property">value</span> = <span class="title function_">reducer</span>(state.<span class="property">value</span>, action)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;state, dispatch&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reducer</span>(<span class="params">state, action</span>) &#123;</span><br><span class="line">    <span class="keyword">switch</span> (action.<span class="property">type</span>) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;reset&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> initialState;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;increment&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> &#123;<span class="attr">count</span>: state.<span class="property">count</span> + <span class="number">1</span>&#125;;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;decrement&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> &#123;<span class="attr">count</span>: state.<span class="property">count</span> - <span class="number">1</span>&#125;;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">useStore</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">useReducer</span>(reducer, initialState);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">useRedux</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">useModel</span>(useStore);  <span class="comment">// 全局 store</span></span><br><span class="line">&#125;</span><br><span class="line">&lt;button @click=<span class="string">&quot;dispatch(&#123;type: &#x27;decrement&#x27;&#125;)&quot;</span>&gt;-&lt;/button&gt;</span><br><span class="line"><span class="keyword">const</span> &#123;state, dispatch&#125; = <span class="title function_">useStore</span>()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">debounce</span>(<span class="params">cb, delay=<span class="number">100</span></span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> timer</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line">        <span class="keyword">let</span> args = <span class="variable language_">arguments</span>,</span><br><span class="line">            context = <span class="variable language_">this</span></span><br><span class="line">        timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            cb.<span class="title function_">apply</span>(context, args)</span><br><span class="line">        &#125;, delay)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">useDebounce</span>(<span class="params">cb, delay = <span class="number">100</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> timer = <span class="title function_">ref</span>(<span class="literal">null</span>)</span><br><span class="line">    <span class="keyword">let</span> handler = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="built_in">clearTimeout</span>(timer.<span class="property">value</span>)</span><br><span class="line">        <span class="keyword">let</span> args = <span class="variable language_">arguments</span>,</span><br><span class="line">            context = <span class="variable language_">this</span></span><br><span class="line">        timer.<span class="property">value</span> = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            cb.<span class="title function_">apply</span>(context, args)</span><br><span class="line">        &#125;, delay)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">cancel</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line">        timer.<span class="property">value</span> = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;handler, cancel&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">useThrottle</span>(<span class="params">cb, duration = <span class="number">100</span></span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> start = +<span class="keyword">new</span> <span class="title class_">Date</span>()</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> args = <span class="variable language_">arguments</span></span><br><span class="line">        <span class="keyword">let</span> context = <span class="variable language_">this</span></span><br><span class="line">        <span class="keyword">let</span> now = +<span class="keyword">new</span> <span class="title class_">Date</span>()</span><br><span class="line">        <span class="keyword">if</span> (now - start &gt;= duration) &#123;</span><br><span class="line">            cb.<span class="title function_">apply</span>(context, args)</span><br><span class="line">            start = now</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> usePage.js 封装分页工具函数，参数对象如下：</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Object</span>&#125;   <span class="variable">condition</span>      -- 查询参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">getListApi</span>     -- 获取列表数据的接口</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">getListFunc</span>    -- 获取数据成功后执行</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">resetFunc</span>      -- 清空查询条件后执行</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">sizeChangeFunc</span> -- 页码改变后执行</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">numChangeFunc</span>  -- 单页数量改变后执行</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Function</span>&#125; <span class="variable">initData</span> -- 用于重置对象字段为原始值的函数</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">import</span> &#123; reactive, ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; initData &#125; <span class="keyword">from</span> <span class="string">&#x27;@/utils/tool&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">usePage</span> = (<span class="params">option</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123;</span><br><span class="line">        condition = &#123;&#125;,</span><br><span class="line">        getListApi,</span><br><span class="line">        getListFunc = <span class="function">(<span class="params">opts</span>) =&gt;</span> &#123;&#125;,</span><br><span class="line">        resetFunc = <span class="function">() =&gt;</span> &#123;&#125;,</span><br><span class="line">        sizeChangeFunc = <span class="function">() =&gt;</span> &#123;&#125;,</span><br><span class="line">        numChangeFunc = <span class="function">() =&gt;</span> &#123;&#125;</span><br><span class="line">    &#125; = option</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">reset</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="title class_">Object</span>.<span class="title function_">assign</span>(condition, <span class="title function_">initData</span>(condition))</span><br><span class="line">        <span class="title function_">resetFunc</span>()</span><br><span class="line">        <span class="title function_">handleNumChange</span>(<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> page = <span class="title function_">reactive</span>(&#123;</span><br><span class="line">        <span class="attr">pageSize</span>: <span class="number">10</span>,</span><br><span class="line">        <span class="attr">pageNum</span>: <span class="number">1</span>,</span><br><span class="line">        <span class="attr">total</span>: <span class="number">0</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">const</span> tableData = <span class="title function_">ref</span>([])</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">getList</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">const</span> opts = &#123;</span><br><span class="line">            ...page,</span><br><span class="line">            ...condition</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title function_">getListApi</span>(opts).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (res.<span class="property">code</span> != <span class="number">0</span>) &#123; <span class="keyword">return</span> &#125;</span><br><span class="line">            tableData.<span class="property">value</span> = res.<span class="property">data</span>?.<span class="property">rows</span> || []</span><br><span class="line">            page.<span class="property">total</span> = res.<span class="property">data</span>?.<span class="property">total</span> || <span class="number">0</span></span><br><span class="line">            <span class="title function_">getListFunc</span>(opts)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">handleSizeChange</span> = (<span class="params">size</span>) =&gt; &#123;</span><br><span class="line">        page.<span class="property">pageSize</span> = size</span><br><span class="line">        <span class="title function_">sizeChangeFunc</span>()</span><br><span class="line">        <span class="title function_">getList</span>()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">handleNumChange</span> = (<span class="params">cur</span>) =&gt; &#123;</span><br><span class="line">        page.<span class="property">pageNum</span> = cur</span><br><span class="line">        <span class="title function_">numChangeFunc</span>()</span><br><span class="line">        <span class="title function_">getList</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        condition,</span><br><span class="line">        reset,</span><br><span class="line">        page,</span><br><span class="line">        tableData,</span><br><span class="line">        handleSizeChange,</span><br><span class="line">        handleNumChange</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件使用：首次获取数据使用 reset 方式， tableData 数据会自动更新</span></span><br><span class="line"><span class="keyword">import</span> &#123; reactive, ref, computed &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; usePage &#125; <span class="keyword">from</span> <span class="string">&#x27;@/composables/usePage&#x27;</span></span><br><span class="line"><span class="keyword">const</span> condition = <span class="title function_">reactive</span>(&#123;</span><br><span class="line">    <span class="title class_">IsEffective</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="title class_">Code</span>: &#123; <span class="attr">$regex</span>: <span class="string">&#x27;2023&#x27;</span>, <span class="attr">$options</span>: <span class="string">&#x27;i&#x27;</span> &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">const</span> &#123; reset, page, tableData, handleSizeChange &#125; = <span class="title function_">usePage</span>(&#123;</span><br><span class="line">    condition,</span><br><span class="line">    getListApi</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title function_">reset</span>()</span><br></pre></td></tr></table></figure>

<h2 id="Tailwind-样式"><a href="#Tailwind-样式" class="headerlink" title="Tailwind 样式"></a>Tailwind 样式</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 主要特点：样式原子化、功能类优先、响应式模式、移动优先的断点系统。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 类名原子化：预定义一组组单一功能单元的类名，区别于组件库的组件化。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 功能类优先：基于一组受约束的原始功能类自定义类名而无需编写 CSS。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 响应式模式：每个功能类都可以有条件的应用于不同断点而无需媒体查询。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 断点系统：加前缀仅在指定断点及以上屏幕生效，未加则在所有屏幕有效。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> JIT 编译器：通过插件 PurgeCSS </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 主要缺点：只适合于定制化高的页面、封装所有属性而导致文件很大。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> PurgeCSS：项目构建时删除掉所有没用到的样式，减少文件的工具。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Vue 项目集成：main.ts </span></span><br><span class="line">npm install -D tailwindcss@latest postcss@latest autoprefixer@latest</span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;tailwindcss/tailwind.css&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// React/Vue 之外的框架集成：tw.css、实时编译命令</span></span><br><span class="line">@tailwind base;</span><br><span class="line">@tailwind components;</span><br><span class="line">@tailwind utilities;</span><br><span class="line">npx tailwindcss -i ./styles/tw.<span class="property">css</span> -o ./styles/index.<span class="property">css</span> --watch</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> tailwind.config.js 配置文件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desp</span>  文件生成 npx tailwindcss init</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> theme：字体、颜色等视觉定义</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> variants：状体修饰定义</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> plugins：引入外部定义 js 样式插件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> presets：自定义基础类，替代默认 base</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> prefix：添加自定义类前缀，方式与其他样式库冲突</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> corePlugins：按需设置需要的生成类, 优化包体积</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">ISProd</span> = process.<span class="property">env</span>.<span class="property">NODE_ENV</span> == <span class="string">&#x27;prod&#x27;</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">    <span class="attr">mode</span>: <span class="string">&#x27;jit&#x27;</span>,            <span class="comment">// 启用 JIT 模式</span></span><br><span class="line">    <span class="attr">presets</span>: []             <span class="comment">// 外部自定义配置</span></span><br><span class="line">    <span class="attr">prefix</span>: <span class="string">&#x27;postcss-&#x27;</span>,     <span class="comment">// 自定义类名前缀</span></span><br><span class="line">    <span class="attr">theme</span>: &#123;</span><br><span class="line">        <span class="comment">// 响应断点 、间距、调色盘、字体、自定义基础类</span></span><br><span class="line">        <span class="attr">screens</span>: &#123; <span class="attr">sm</span>: <span class="string">&#x27;640px&#x27;</span>, <span class="attr">md</span>: <span class="string">&#x27;768px&#x27;</span>, <span class="attr">mobile</span>: <span class="string">&#x27;640px&#x27;</span> &#125;,</span><br><span class="line">        <span class="attr">spacing</span>: &#123; <span class="string">&#x27;1&#x27;</span>: <span class="string">&#x27;8px&#x27;</span>, <span class="string">&#x27;2&#x27;</span>: <span class="string">&#x27;12px&#x27;</span>, <span class="string">&#x27;3&#x27;</span>: <span class="string">&#x27;16px&#x27;</span> &#125;,</span><br><span class="line">        <span class="attr">colors</span>: &#123; <span class="attr">blue</span>: <span class="string">&#x27;#1fb6ff&#x27;</span>, <span class="attr">pink</span>: <span class="string">&#x27;#ff49db&#x27;</span> &#125;,</span><br><span class="line">        <span class="attr">fontFamily</span>: &#123; <span class="attr">sans</span>: [<span class="string">&#x27;Graphik&#x27;</span>, <span class="string">&#x27;sans-serif&#x27;</span>] &#125;,</span><br><span class="line">        <span class="comment">// 自定义基础类：w-aa、max-w-bb、、text-gg、text-caca</span></span><br><span class="line">        <span class="attr">extend</span>: &#123;   </span><br><span class="line">            <span class="attr">width</span>: &#123; <span class="attr">aa</span>: <span class="string">&#x27;99px&#x27;</span> &#125;,</span><br><span class="line">            <span class="attr">maxWidth</span>: &#123; <span class="attr">bb</span>: <span class="string">&#x27;102px&#x27;</span> &#125;,</span><br><span class="line">            <span class="attr">spacing</span>: &#123; <span class="string">&#x27;128&#x27;</span>: <span class="string">&#x27;32rem&#x27;</span> &#125;,  </span><br><span class="line">            <span class="attr">colors</span>: &#123; <span class="attr">gg</span>: &#123; <span class="attr">light</span>: <span class="string">&#x27;#aca&#x27;</span>, <span class="attr">dark</span>: <span class="string">&#x27;#fca&#x27;</span> &#125; &#125;,</span><br><span class="line">            <span class="attr">fontSize</span>: &#123; <span class="attr">caca</span>: [<span class="string">&#x27;1.75rem&#x27;</span>, &#123; <span class="attr">lineHeight</span>: <span class="string">&#x27;1rem&#x27;</span> &#125;] &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">plugins</span>: [</span><br><span class="line">        <span class="built_in">require</span>(<span class="string">&#x27;tailwindcss&#x27;</span>),</span><br><span class="line">        <span class="built_in">require</span>(<span class="string">&#x27;autoprefixer&#x27;</span>),</span><br><span class="line">        <span class="comment">// cssnano 删除所有注释、purgecss</span></span><br><span class="line">        <span class="title class_">ISProd</span> &amp;&amp; <span class="built_in">require</span>(<span class="string">&#x27;cssnano&#x27;</span>)(&#123;<span class="attr">preset</span>: <span class="string">&#x27;default&#x27;</span>&#125;),</span><br><span class="line">        <span class="title class_">ISProd</span> &amp;&amp; <span class="built_in">require</span>(<span class="string">&quot;@fullhuman/postcss-purgecss&quot;</span>)(&#123;</span><br><span class="line">            <span class="comment">// 清理范围：所有的模版文件</span></span><br><span class="line">            <span class="attr">content</span>: [<span class="string">&#x27;./src/**/*.&#123;html,vue,js,jsx,ts,tsx&#125;&#x27;</span>],</span><br><span class="line">            <span class="comment">// 包括在这个正则表达式中使用的任何特殊字符</span></span><br><span class="line">            <span class="attr">defaultExtractor</span>: <span class="function"><span class="params">con</span> =&gt;</span> con.<span class="title function_">match</span>(<span class="regexp">/[\w-/:]+(?&lt;!:)/g</span>) || []</span><br><span class="line">            <span class="comment">// 不作处理的类名白名单</span></span><br><span class="line">            <span class="attr">whitelist</span>: [<span class="string">&#x27;html&#x27;</span>, <span class="string">&#x27;body&#x27;</span>],</span><br><span class="line">            <span class="attr">whitelistPatterns</span>: [<span class="regexp">/el-.+$/</span>],</span><br><span class="line">            <span class="attr">whitelistPatternsChildren</span>: [<span class="regexp">/el-.+$/</span>]</span><br><span class="line">        &#125;)</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// html</span></span><br><span class="line">&lt;div <span class="keyword">class</span>=<span class="string">&quot;text-center sm:text-left&quot;</span>&gt;移动布局、响应布局(断点名:功能类)&lt;/div&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;text-[22px] lg:top-[34px]&quot;</span>&gt;</span>自定义样式<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">img</span> <span class="attr">class</span>=<span class="string">&quot;w-16 md:w-32 lg:w-48&quot;</span> <span class="attr">src</span>=<span class="string">&quot;/src/logo.png&quot;</span> /&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> tw.css</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 原子化类名示例</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 背景：bg-white、bg-gray-50, bg-gradient-to-bl</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 布局：container、flex-1、flex-auto、grid-cols-1</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 内外边距：p-0、px-1.5、-m-px、mt-1、space-x-0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 尺寸：w-1、w-full、max-w-xl、h-1、min-h-full</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 字体：font-sans、text-xs、text-lg、font-thin</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 函数与指令</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@tailwind</span> 引入基础、组件、原子、媒体等样式类。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@apply</span> 将一系列已有的功能类内联到自定义样式。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@layer</span> 将自定义的样式代码添加到对应类的分组。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@variants</span> 指定各状态类或者其变体。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@responsive</span> 生成默认响应式类变体。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="doctag">@screen</span> 通过名称引用断点的媒体查询。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> theme() 通过点符号获取主题样式。</span></span><br><span class="line"><span class="comment">**/</span>  </span><br><span class="line">@tailwind base;         </span><br><span class="line">@tailwind components;</span><br><span class="line">@tailwind utilities;</span><br><span class="line">@tailwind screens;</span><br><span class="line">@layer base &#123;</span><br><span class="line">    h1 &#123; font-<span class="attr">size</span>: <span class="number">1.</span>5rem; &#125;</span><br><span class="line">&#125;</span><br><span class="line">@layer components &#123;  </span><br><span class="line">    .<span class="property">btn</span> &#123;</span><br><span class="line">        <span class="comment">// scss 语法需使用 #&#123;!important&#125;</span></span><br><span class="line">        @apply font-bold py-<span class="number">2</span> px-<span class="number">4</span> rounded !important;</span><br><span class="line">    &#125;</span><br><span class="line">    .<span class="property">btn</span>-blue &#123;</span><br><span class="line">        @apply text-white bg-green-<span class="number">500</span> <span class="attr">hover</span>:bg-green-<span class="number">700</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">@variants focus, hover &#123;</span><br><span class="line">    .<span class="property">rotate</span>-<span class="number">0</span> &#123;</span><br><span class="line">        <span class="attr">transform</span>: <span class="title function_">rotate</span>(0deg);</span><br><span class="line">    &#125;</span><br><span class="line">    .<span class="property">rotate</span>-<span class="number">90</span> &#123;</span><br><span class="line">        <span class="attr">transform</span>: <span class="title function_">rotate</span>(90deg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">@responsive &#123;</span><br><span class="line">    .<span class="property">bg</span>-color&#123;</span><br><span class="line">        <span class="attr">background</span>: orange;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">@screen sm &#123;     <span class="comment">// @media (min-width: 640px)&#123; .sm:bg-color&#123;&#125; &#125;</span></span><br><span class="line">    .<span class="property">bg</span>-color &#123;</span><br><span class="line">        <span class="attr">background</span>: orange;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">.<span class="property">content</span>-area &#123;</span><br><span class="line">    <span class="attr">height</span>: <span class="title function_">calc</span>(100vh - <span class="title function_">theme</span>(<span class="string">&#x27;spacing.12&#x27;</span>));</span><br><span class="line">    <span class="attr">height</span>: <span class="title function_">calc</span>(100vh - <span class="title function_">theme</span>(<span class="string">&#x27;spacing[2.5]&#x27;</span>));</span><br><span class="line">    background-<span class="attr">color</span>: <span class="title function_">theme</span>(<span class="string">&#x27;colors.blue.500&#x27;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> CSS Modules 切换到 Tailwind CSS</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 1、VSCode 下载插件：Tailwind CSS IntelliSense</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 2、安装 tailwind：npm install -D tailwindcss</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 3、生成配置文件：npx tailwindcss init</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 4、样式入口文件引入：tw.css</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 5、命令处理旧代码 JSX/TSX </span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">/** <span class="doctag">@type</span> &#123;<span class="type">import(&#x27;tailwindcss&#x27;).Config</span>&#125; */</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">    <span class="attr">important</span>: <span class="literal">true</span>,          <span class="comment">// !important 设置优先级</span></span><br><span class="line">    <span class="attr">content</span>: [<span class="string">&#x27;./src/**/*.&#123;ts,tsx&#125;&#x27;</span>, <span class="string">&#x27;./src/**/*.&#123;css,scss&#125;&#x27;</span>],</span><br><span class="line">    <span class="attr">corePlugins</span>: &#123; <span class="attr">preflight</span>: <span class="literal">false</span> &#125;,  <span class="comment">// 禁用默认的全局基本样式</span></span><br><span class="line">    <span class="attr">theme</span>: &#123;</span><br><span class="line">        <span class="attr">extend</span>: &#123;</span><br><span class="line">            <span class="attr">fontSize</span>: &#123;      <span class="comment">// 排除行高的影响</span></span><br><span class="line">                <span class="attr">xs</span>: <span class="string">&#x27;12px&#x27;</span>,</span><br><span class="line">                <span class="attr">sm</span>: <span class="string">&#x27;14px&#x27;</span>,</span><br><span class="line">                <span class="attr">base</span>: <span class="string">&#x27;16px&#x27;</span>,</span><br><span class="line">                <span class="attr">lg</span>: <span class="string">&#x27;18px&#x27;</span>,</span><br><span class="line">                <span class="attr">xl</span>: <span class="string">&#x27;20px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;2xl&#x27;</span>: <span class="string">&#x27;24px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;3xl&#x27;</span>: <span class="string">&#x27;30px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;4xl&#x27;</span>: <span class="string">&#x27;36px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;5xl&#x27;</span>: <span class="string">&#x27;48px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;6xl&#x27;</span>: <span class="string">&#x27;60px&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;7xl&#x27;</span>: <span class="string">&#x27;72px&#x27;</span>,</span><br><span class="line">            &#125;,</span><br><span class="line">            <span class="attr">textColor</span>: &#123; <span class="number">666</span>: <span class="string">&#x27;#666&#x27;</span> &#125;    <span class="comment">// text-666</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">plugins</span>: [],</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// tw.css：入口样式文件</span></span><br><span class="line">@tailwind base;</span><br><span class="line">@tailwind components;</span><br><span class="line">@tailwind utilities;</span><br><span class="line">.<span class="property">html</span> &#123; font-<span class="attr">size</span>: 16px; &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理旧代码 JSX/TSX </span></span><br><span class="line">npx css-modules-to-tailwind src<span class="comment">/**/</span>*.<span class="property">tsx</span> -f</span><br></pre></td></tr></table></figure>


<h1 id="二、组件开发"><a href="#二、组件开发" class="headerlink" title="二、组件开发"></a>二、组件开发</h1><h2 id="组件注册"><a href="#组件注册" class="headerlink" title="组件注册"></a>组件注册</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 局部注册</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">IonApp</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@ionic/vue&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123; <span class="attr">components</span>: &#123; <span class="title class_">IonApp</span> &#125; &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 全局注册：main.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; createApp &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">&#x27;./App.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Swiper</span> <span class="keyword">from</span> <span class="string">&#x27;./components/MySwiper.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">MyCom</span> <span class="keyword">from</span> <span class="string">&#x27;./components/MyCom.vue&#x27;</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">createApp</span>(<span class="title class_">App</span>)</span><br><span class="line">app.<span class="title function_">component</span>(<span class="string">&#x27;MyCom&#x27;</span>, <span class="title class_">Test</span>)</span><br><span class="line">app.<span class="title function_">component</span>(<span class="string">&#x27;my-swiper&#x27;</span>, <span class="title class_">Swiper</span>)</span><br><span class="line">app.<span class="title function_">mount</span>(<span class="string">&#x27;#app&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// vue3 全局组件手动注册：main.js、components/IonicBase.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">IonicBase</span> <span class="keyword">from</span> <span class="string">&#x27;@/components/IonicBase&#x27;</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title class_">IonicBase</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">IonTitle</span>, <span class="title class_">IonContent</span>, <span class="title class_">IonButton</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@ionic/vue&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="title function_">install</span>(<span class="params">app</span>) &#123;</span><br><span class="line">        app.<span class="title function_">component</span>(<span class="string">&#x27;IonTitle&#x27;</span>, <span class="title class_">IonTitle</span>);</span><br><span class="line">        app.<span class="title function_">component</span>(<span class="string">&#x27;IonContent&#x27;</span>, <span class="title class_">IonContent</span>);</span><br><span class="line">        app.<span class="title function_">component</span>(<span class="string">&#x27;IonButton&#x27;</span>, <span class="title class_">IonButton</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// vue3 全局组件自动注册：main.js、ComponentRegister.ts</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">ComponentRegister</span> <span class="keyword">from</span> <span class="string">&#x27;./plugins/component&#x27;</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title class_">ComponentRegister</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">App</span>, defineAsyncComponent &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">const</span> modules = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="title function_">glob</span>(<span class="string">&#x27;../components/common/*.vue&#x27;</span>)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="title function_">install</span>(<span class="params">app: App, obtions: any</span>) &#123;</span><br><span class="line">        <span class="title class_">Object</span>.<span class="title function_">keys</span>(modules).<span class="title function_">forEach</span>(<span class="function"><span class="params">name</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> component = modules[name].<span class="property">default</span></span><br><span class="line">            app.<span class="title function_">component</span>(component.<span class="property">name</span>, component)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// import.meta.glob 转译结果：import.meta.globEager 为同步导入</span></span><br><span class="line"><span class="keyword">const</span> modules = &#123;</span><br><span class="line">  <span class="string">&#x27;./components/a.vue&#x27;</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;./components/a.vue&#x27;</span>),</span><br><span class="line">  <span class="string">&#x27;./components/b.vue&#x27;</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;./components/b.vue&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// vue2 main.js 全局组件自动注册：vite 不支持 require.context</span></span><br><span class="line"><span class="keyword">const</span> modules = <span class="built_in">require</span>.<span class="title function_">context</span>(<span class="string">&#x27;./&#x27;</span>, <span class="literal">true</span>, <span class="regexp">/index.(vue|js)$/</span>)</span><br><span class="line">modules.<span class="title function_">keys</span>().<span class="title function_">forEach</span>(<span class="function"><span class="params">filename</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> component = <span class="title function_">modules</span>(filename).<span class="property">default</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="regexp">/.vue$/</span>.<span class="title function_">test</span>(filename)) &#123;</span><br><span class="line">        <span class="title class_">Vue</span>.<span class="title function_">component</span>(component.<span class="property">name</span>, component)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="regexp">/.js/</span>.<span class="title function_">test</span>(filename)) &#123;</span><br><span class="line">        <span class="title class_">Vue</span>.<span class="title function_">use</span>(component)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h2 id="模拟数据"><a href="#模拟数据" class="headerlink" title="模拟数据"></a>模拟数据</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 安装后配置 vite.config.ts viteMockServe</span></span><br><span class="line">npm install mockjs vite-plugin-mock -D</span><br><span class="line"></span><br><span class="line"><span class="comment">// src/mock/source/user.ts</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Mock</span>, &#123; <span class="title class_">Random</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;mockjs&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">MockMethod</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;vite-plugin-mock&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> [</span><br><span class="line">  &#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;/api/getUserInfo&#x27;</span>,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;get&#x27;</span>,</span><br><span class="line">      <span class="attr">response</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">return</span> &#123;</span><br><span class="line">              <span class="attr">menu</span>: [</span><br><span class="line">                  &#123; <span class="attr">id</span>: <span class="string">&#x27;1&#x27;</span>, <span class="attr">title</span>: <span class="string">&#x27;南辰&#x27;</span>, <span class="attr">subMenu</span>: [</span><br><span class="line">                      &#123; <span class="attr">id</span>: <span class="string">&#x27;11&#x27;</span>, <span class="attr">title</span>: <span class="string">&#x27;南&#x27;</span>, <span class="attr">path</span>: <span class="string">&#x27;/user/nan&#x27;</span>&#125;,</span><br><span class="line">                      &#123; <span class="attr">id</span>: <span class="string">&#x27;12&#x27;</span>, <span class="attr">title</span>: <span class="string">&#x27;小&#x27;</span>, <span class="attr">path</span>: <span class="string">&#x27;/user/xiao&#x27;</span> &#125;,</span><br><span class="line">                  ]&#125;, </span><br><span class="line">                  &#123; <span class="attr">id</span>: <span class="string">&#x27;2&#x27;</span>, <span class="attr">title</span>: <span class="string">&#x27;戏&#x27;</span>, <span class="attr">subMenu</span>: [</span><br><span class="line">                      &#123; <span class="attr">id</span>: <span class="string">&#x27;21&#x27;</span>, <span class="attr">title</span>: <span class="string">&#x27;游戏&#x27;</span>, <span class="attr">path</span>: <span class="string">&#x27;/user/play&#x27;</span>&#125;</span><br><span class="line">                  ]&#125;</span><br><span class="line">              ]</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">      <span class="attr">url</span>: <span class="string">&#x27;/api/createUser&#x27;</span>,</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;get&#x27;</span>,</span><br><span class="line">      <span class="attr">response</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">return</span> &#123;</span><br><span class="line">              <span class="attr">code</span>: <span class="number">200</span>,</span><br><span class="line">              <span class="attr">message</span>: <span class="string">&#x27;ok&#x27;</span>,</span><br><span class="line">              <span class="attr">data</span>: <span class="title class_">Mock</span>.<span class="title function_">mock</span>(&#123;</span><br><span class="line">                  <span class="string">&#x27;list|4&#x27;</span>: [&#123;</span><br><span class="line">                      <span class="attr">id</span>: <span class="string">&#x27;@id&#x27;</span>,</span><br><span class="line">                      <span class="attr">name</span>: <span class="string">&#x27;@cname&#x27;</span>,</span><br><span class="line">                      <span class="attr">age</span>: <span class="title class_">Random</span>.<span class="title function_">integer</span>(<span class="number">1</span>, <span class="number">100</span>),</span><br><span class="line">                      <span class="attr">address</span>: <span class="string">&#x27;@county&#x27;</span>,</span><br><span class="line">                      <span class="attr">city</span>: <span class="string">&#x27;@city&#x27;</span>,</span><br><span class="line">                      <span class="attr">province</span>: <span class="string">&#x27;@province&#x27;</span>,</span><br><span class="line">                      <span class="attr">email</span>: <span class="title class_">Random</span>.<span class="title function_">email</span>(),</span><br><span class="line">                      <span class="attr">phone</span>: <span class="regexp">/^1[0-9]&#123;10&#125;$/</span>,</span><br><span class="line">                      <span class="attr">regin</span>: <span class="string">&#x27;@region&#x27;</span>,</span><br><span class="line">                      <span class="attr">url</span>: <span class="string">&#x27;@url&#x27;</span>,</span><br><span class="line">                      <span class="attr">date</span>: <span class="title class_">Random</span>.<span class="title function_">date</span>(<span class="string">&#x27;yyyy-MM-dd&#x27;</span>)</span><br><span class="line">                  &#125;]</span><br><span class="line">              &#125;)</span><br><span class="line">          &#125;;</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line">] <span class="keyword">as</span> <span class="title class_">MockMethod</span>[];</span><br></pre></td></tr></table></figure>


<h2 id="静态资源"><a href="#静态资源" class="headerlink" title="静态资源"></a>静态资源</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">img</span> <span class="attr">v-if</span>=<span class="string">&quot;type == &#x27;img&#x27;&quot;</span> <span class="attr">:src</span>=<span class="string">&quot;envSrc&quot;</span> /&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">video</span> <span class="attr">v-else-if</span>=<span class="string">&quot; type === &#x27;video&#x27;&quot;</span> <span class="attr">muted</span>  </span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">ref</span>=<span class="string">&quot;videoRef&quot;</span> <span class="attr">:poster</span>=<span class="string">&quot;poster&quot;</span> /&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">audio</span> <span class="attr">v-else</span> <span class="attr">:src</span>=<span class="string">&quot;envSrc&quot;</span> /&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="comment">// withDefaults：对默认值的类型检查、删除已声明默认值的属性的可选标志。</span></span><br><span class="line"><span class="keyword">import</span> &#123;computed, ref, withDefaults, onMounted, watch&#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> useDevice <span class="keyword">from</span> <span class="string">&#x27;@/hooks/useDevice&#x27;</span>;</span><br><span class="line">interface <span class="title class_">Props</span> &#123; src?: string; type?: string; autoplay?: boolean; &#125;</span><br><span class="line"><span class="keyword">const</span> props = <span class="title function_">withDefaults</span>(defineProps&lt;<span class="title class_">Props</span>&gt;(), &#123;</span><br><span class="line">    <span class="attr">src</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&#x27;img&#x27;</span>,</span><br><span class="line">    <span class="attr">autoplay</span>: <span class="literal">true</span>,</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">getStaticUrl</span> = (<span class="params">url: string</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title function_">URL</span>(<span class="string">`../images/<span class="subst">$&#123;url&#125;</span>`</span>, <span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">url</span>).<span class="property">href</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> envSrc = <span class="title function_">getStaticUrl</span>(props.<span class="property">src</span>);</span><br><span class="line"><span class="comment">// 处理视频自动播放：解决 chrome 无法自动播放的问题</span></span><br><span class="line"><span class="keyword">const</span> &#123; deviceType &#125; = <span class="title function_">useDevice</span>();</span><br><span class="line"><span class="keyword">const</span> poster = <span class="title function_">computed</span>(<span class="function">() =&gt;</span></span><br><span class="line">    deviceType.<span class="property">value</span> === <span class="string">&#x27;desktop&#x27;</span> ? <span class="string">&#x27;&#x27;</span> : envSrc</span><br><span class="line">);</span><br><span class="line"><span class="keyword">const</span> videoRef = ref&lt;<span class="title class_">HTMLVideoElement</span>&gt;(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 解决移动端视频无法自动播放的问题</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">videoAutoPlay</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (props.<span class="property">type</span> === <span class="string">&#x27;video&#x27;</span> &amp;&amp; videoRef.<span class="property">value</span> !== <span class="literal">null</span>) &#123;</span><br><span class="line">        videoRef.<span class="property">value</span>.<span class="property">src</span> = envSrc;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (props.<span class="property">autoplay</span> &amp;&amp; videoRef.<span class="property">value</span>) &#123;</span><br><span class="line">        videoRef.<span class="property">value</span>.<span class="property">oncanplay</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (videoRef.<span class="property">value</span>) videoRef.<span class="property">value</span>.<span class="title function_">play</span>();</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 自动播放视频</span></span><br><span class="line"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123; <span class="title function_">videoAutoPlay</span>();&#125;);</span><br><span class="line"><span class="comment">// 监听视频 src，如果存在则自动播放</span></span><br><span class="line"><span class="title function_">watch</span>(envSrc, <span class="function">() =&gt;</span> &#123; <span class="keyword">if</span> (videoRef.<span class="property">value</span>) videoRef.<span class="property">value</span>.<span class="title function_">play</span>(); &#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span>  hooks 工具集</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@method</span> useDevice      运行设备</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@method</span> useClipboard   复制功能</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@method</span> useFullscreen  全屏功能</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> device <span class="keyword">from</span> <span class="string">&#x27;current-device&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">useDevice</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> deviceType = <span class="title function_">ref</span>(device.<span class="property">type</span>);</span><br><span class="line">    <span class="keyword">const</span> deviceOrientation = <span class="title function_">ref</span>(device.<span class="property">orientation</span>);</span><br><span class="line">    <span class="keyword">const</span> deviceOs = <span class="title function_">ref</span>(device.<span class="property">os</span>);</span><br><span class="line">    <span class="keyword">return</span> &#123; deviceType, deviceOrientation, deviceOs &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">type clipboardResult = &#123;</span><br><span class="line">    <span class="attr">copyText</span>: <span class="function">(<span class="params">text: string</span>) =&gt;</span> <span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">const</span> useClipboard = (): <span class="function"><span class="params">clipboardResult</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> el = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;div&#x27;</span>);</span><br><span class="line">    el.<span class="property">style</span>.<span class="property">whiteSpace</span> = <span class="string">&#x27;pre&#x27;</span>;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">copyText</span> = (<span class="params">text?: string</span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (!text) <span class="keyword">return</span>;</span><br><span class="line">        <span class="keyword">const</span> selection = <span class="variable language_">window</span>.<span class="title function_">getSelection</span>();</span><br><span class="line">        <span class="keyword">if</span> (!selection) <span class="keyword">return</span>;</span><br><span class="line">        <span class="keyword">const</span> range = <span class="variable language_">document</span>.<span class="title function_">createRange</span>();</span><br><span class="line">        el.<span class="property">textContent</span> = text;</span><br><span class="line">        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(el);</span><br><span class="line">        range.<span class="title function_">selectNode</span>(el);</span><br><span class="line">        selection.<span class="title function_">removeAllRanges</span>();</span><br><span class="line">        selection.<span class="title function_">addRange</span>(range);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable language_">document</span>.<span class="title function_">execCommand</span>(<span class="string">&#x27;Copy&#x27;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;copy failed!&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        selection.<span class="title function_">removeAllRanges</span>();</span><br><span class="line">        el.<span class="property">textContent</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">removeChild</span>(el);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">return</span> &#123; copyText &#125;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> screenfull <span class="keyword">from</span> <span class="string">&#x27;screenfull&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">useFullscreen</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> screenfullActive = <span class="title function_">ref</span>(<span class="literal">false</span>);</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toggleScreenfull</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!screenfull.<span class="property">isEnabled</span>) <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">if</span> (screenfull.<span class="property">isFullscreen</span>) &#123;</span><br><span class="line">            screenfull.<span class="title function_">exit</span>();</span><br><span class="line">            screenfullActive.<span class="property">value</span> = <span class="literal">false</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            screenfull.<span class="title function_">request</span>();</span><br><span class="line">            screenfullActive.<span class="property">value</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">openScreenfull</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!screenfull.<span class="property">isEnabled</span>) <span class="keyword">return</span></span><br><span class="line">        screenfull.<span class="title function_">request</span>();</span><br><span class="line">        screenfullActive.<span class="property">value</span> = <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">closeScreenfull</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!screenfull.<span class="property">isEnabled</span>) <span class="keyword">return</span></span><br><span class="line">        screenfull.<span class="title function_">exit</span>();</span><br><span class="line">        screenfullActive.<span class="property">value</span> = <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        screenfullActive, </span><br><span class="line">        toggleScreenfull, </span><br><span class="line">        openScreenfull, </span><br><span class="line">        closeScreenfull,</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="事件联动"><a href="#事件联动" class="headerlink" title="事件联动"></a>事件联动</h2><blockquote>
<p>组件实例的 $on、$off、$once 已废弃而无法监听事件，可通过小体积的第三方库 mitt。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 基础使用</span></span><br><span class="line"><span class="keyword">import</span> mitt <span class="keyword">from</span> <span class="string">&#x27;mitt&#x27;</span></span><br><span class="line"><span class="keyword">const</span> emitter = <span class="title function_">mitt</span>()</span><br><span class="line">emitter.<span class="title function_">on</span>(<span class="string">&#x27;foo&#x27;</span>, onFoo) </span><br><span class="line">emitter.<span class="title function_">emit</span>(<span class="string">&#x27;foo&#x27;</span>, &#123;<span class="attr">a</span>: <span class="number">1</span>&#125;)</span><br><span class="line">emitter.<span class="title function_">off</span>(<span class="string">&#x27;foo&#x27;</span>, onFoo)  <span class="comment">// 取消订阅：onFoo 可省略</span></span><br><span class="line">emitter.<span class="title function_">on</span>(<span class="string">&#x27;*&#x27;</span>, <span class="function">(<span class="params">type, e</span>) =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(type, e))</span><br><span class="line">emitter.<span class="property">all</span>.<span class="title function_">clear</span>()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// main.ts：必须拓展 ComponentCustomProperties</span></span><br><span class="line"><span class="keyword">import</span> emitter <span class="keyword">from</span> <span class="string">&quot;@/utils/emitter&quot;</span>;</span><br><span class="line">app.<span class="property">config</span>.<span class="property">globalProperties</span>.<span class="property">$emitter</span> = emitter</span><br><span class="line">declare <span class="variable language_">module</span> <span class="string">&quot;vue&quot;</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> interface <span class="title class_">ComponentCustomProperties</span> &#123;</span><br><span class="line">        <span class="attr">$emitter</span>: <span class="keyword">typeof</span> emitter;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 组件使用：setup 是否存在</span></span><br><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineComponent</span>(&#123;</span><br><span class="line">        <span class="title function_">mounted</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">$emitter</span>.<span class="title function_">on</span>(<span class="string">&quot;foo&quot;</span>, <span class="function">() =&gt;</span> &#123; &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">&lt;/script&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; getCurrentInstance &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> instance = <span class="title function_">getCurrentInstance</span>();</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    instance?.<span class="property">proxy</span>?.<span class="property">$emitter</span>.<span class="title function_">on</span>(<span class="string">&quot;foo&quot;</span>, <span class="function">() =&gt;</span> &#123; &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>




<h1 id="三、组件通信"><a href="#三、组件通信" class="headerlink" title="三、组件通信"></a>三、组件通信</h1><blockquote>
<p>Pinia 实现跨组件通信的官方状态管理工具此处省略用法。</p>
</blockquote>
<h2 id="props-x2F-expose"><a href="#props-x2F-expose" class="headerlink" title="props&#x2F;expose"></a>props&#x2F;expose</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Parent.vue</span></span><br><span class="line">&lt;template&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">child</span> <span class="attr">:msg</span>=<span class="string">&quot;msg&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;comp&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;handlerClick&quot;</span>&gt;</span>按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> child <span class="keyword">from</span> <span class="string">&quot;./child.vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; ref, reactive &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> msg = <span class="title function_">ref</span>(<span class="string">&quot;父传子的信息&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> msg = <span class="title function_">reactive</span>([<span class="string">&quot;父传子的信息&quot;</span>])</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> <span class="title function_">handlerClick</span> = (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">const</span> comp = <span class="title function_">ref</span>(<span class="literal">null</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        comp.<span class="property">value</span>.<span class="title function_">someMethod</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Child.vue</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> props = <span class="title function_">defineProps</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">msg</span>: <span class="title class_">String</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">msg</span>: &#123; <span class="attr">type</span>: <span class="title class_">String</span>, <span class="attr">default</span>: <span class="string">&quot;&quot;</span> / <span class="function">() =&gt;</span> <span class="string">&quot;&quot;</span> &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title function_">defineExpose</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">childName</span>: <span class="string">&quot;子传父的属性&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">someMethod</span>(<span class="params"></span>) &#123; <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;子组件的方法&quot;</span>) &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<h2 id="emit"><a href="#emit" class="headerlink" title="$emit"></a>$emit</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Child.vue：发送</span></span><br><span class="line"><span class="keyword">const</span> emit = <span class="title function_">defineEmits</span>([<span class="string">&quot;onClick&quot;</span>])</span><br><span class="line"><span class="title function_">emit</span>(<span class="string">&#x27;onClick&#x27;</span>, <span class="string">&#x27;数据&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Parent.vue：接收</span></span><br><span class="line">&lt;child @on-click=<span class="string">&quot;onClickTag&quot;</span>&gt;&lt;/child&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> child <span class="keyword">from</span> <span class="string">&quot;./child.vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> <span class="title function_">onClickTag</span> = (<span class="params">msg: <span class="built_in">String</span></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<h2 id="attrs"><a href="#attrs" class="headerlink" title="$attrs"></a>$attrs</h2><blockquote>
<p>Vue2 可以通过 this.$attrs、this.$listeners 分别访问传递给组件的 props 未定义属性和事件监听器，Vue3 $attrs 包括了之前除外的属性 class、style 并合并移除了 $listeners。</p>
</blockquote>
  <figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">// Parent.vue：发送</span><br><span class="line"><span class="tag">&lt;<span class="name">child</span> <span class="attr">:msg</span>=<span class="string">&quot;msg&quot;</span> <span class="attr">title</span>=<span class="string">&quot;3333&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">import</span> child <span class="keyword">from</span> <span class="string">&quot;./child.vue&quot;</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">import</span> &#123; ref, reactive &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> msg = <span class="title function_">ref</span>(<span class="string">&quot;1111&quot;</span>)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line">// Child.vue：接收</span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">inheritAttrs</span>: <span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">import</span> &#123; useAttrs &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> attrs = <span class="title function_">useAttrs</span>()</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="slot"><a href="#slot" class="headerlink" title="slot"></a>slot</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Parent.vue</span></span><br><span class="line">&lt;<span class="title class_">Child</span>&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">span</span>&gt;</span>默认插槽<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">template</span> <span class="attr">v-slot:monkey</span>&gt;</span>具名插槽<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line">&lt;/<span class="title class_">Child</span>&gt;</span><br><span class="line"><span class="comment">// Child.vue</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">&quot;monkey&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> Parent.vue：作用域插槽</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> <span class="variable">v</span>-slot：获取子组件的数据</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> :list：给子组件传递数据 </span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">Child</span> <span class="attr">v-slot</span>=<span class="string">&quot;&#123;scope&#125;&quot;</span> <span class="attr">:list</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>名字：&#123;&#123; scope.name &#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>职业：&#123;&#123; scope.occupation &#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">Child</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> <span class="title class_">Child</span> <span class="keyword">from</span> <span class="string">&#x27;./components/Child.vue&#x27;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> list = <span class="title function_">ref</span>([</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#123; <span class="attr">name</span>: <span class="string">&#x27;雷猴&#x27;</span>, <span class="attr">occupation</span>: <span class="string">&#x27;打雷&#x27;</span>&#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#123; <span class="attr">name</span>: <span class="string">&#x27;鲨鱼辣椒&#x27;</span>, <span class="attr">occupation</span>: <span class="string">&#x27;游泳&#x27;</span>&#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#123; <span class="attr">name</span>: <span class="string">&#x27;蟑螂恶霸&#x27;</span>, <span class="attr">occupation</span>: <span class="string">&#x27;扫地&#x27;</span>&#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    ])</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="comment">// Child.vue</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">slot</span> <span class="attr">v-for</span>=<span class="string">&quot;item in list&quot;</span> <span class="attr">:scope</span>=<span class="string">&quot;item&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> props = <span class="title function_">defineProps</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">list</span>: &#123; <span class="attr">type</span>: <span class="title class_">Array</span>, <span class="attr">default</span>: <span class="function">() =&gt;</span> [] &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>


<h2 id="v-model"><a href="#v-model" class="headerlink" title="v-model"></a>v-model</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Parent.vue</span></span><br><span class="line">&lt;template&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">child</span> <span class="attr">v-model.a</span>=<span class="string">&quot;name&quot;</span> <span class="attr">v-model:value</span>=<span class="string">&quot;value&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> child <span class="keyword">from</span> <span class="string">&quot;./child.vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; ref, reactive &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> name = <span class="title function_">ref</span>(<span class="string">&quot;input&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> value = <span class="title function_">ref</span>(<span class="string">&quot;select&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Child.vue：自定义组件时，v-model prop 和事件的默认名称已更改但可以自定义</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;handlerClick&quot;</span>&gt;</span>按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="comment">// 默认绑定的属性名为 modelValue，通过 : 自定义名称，通过 . 自定义修饰符</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> props = <span class="title function_">defineProps</span>(<span class="string">&quot;modelValue&quot;</span>, <span class="string">&quot;modelModifiers&quot;</span>, <span class="string">&quot;value&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> emit = <span class="title function_">defineEmits</span>([<span class="string">&quot;update:modelValue&quot;</span>, <span class="string">&quot;update:value&quot;</span>])</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> <span class="title function_">handlerClick</span> = (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">modelModifiers</span>.<span class="property">a</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">emit</span>(<span class="string">&quot;update:modelValue&quot;</span>, <span class="string">&quot;new name&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title function_">emit</span>(<span class="string">&quot;update:value&quot;</span>, <span class="string">&quot;new value&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<h2 id="provide-x2F-inject"><a href="#provide-x2F-inject" class="headerlink" title="provide&#x2F;inject"></a>provide&#x2F;inject</h2><blockquote>
<p>实现树形组件的依赖注入功能，常用于层级嵌套较深的组件之间相互传递数据。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Parent.vue：所有后代组件的依赖提供者</span></span><br><span class="line">&lt;script setup&gt;</span><br><span class="line">    <span class="keyword">import</span> &#123; provide &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span><br><span class="line">    <span class="title function_">provide</span>(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;传给子孙的数据&quot;</span>)</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Child.vue：依赖使用者</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">import</span> &#123; inject &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> name = <span class="title function_">inject</span>(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;默认值&quot;</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>


<h1 id="四、案例"><a href="#四、案例" class="headerlink" title="四、案例"></a>四、案例</h1><p><a target="_blank" rel="external nofollow noopener noreferrer" href="https://juejin.cn/post/7154579554034515982">Pinia 登录案例</a></p>
<p><a target="_blank" rel="external nofollow noopener noreferrer" href="https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651616698&idx=1&sn=e5b812c4a490b8dd02b3cbb8ae3f1853&chksm=8022a27bb7552b6df77ecc38a0db72583fa4fadc5dd2daaa63d4c3badac18271da9d52554787&scene=126&sessionid=1695174598#rd">Vue3+Pinia+Koa+Three.js</a></p>

    </div>

    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;margin-top:20px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>chuangges
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://chuangges.gitee.io/2023/03/02/21-vue3%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/" title="Vue3 项目开发">https://chuangges.gitee.io/2023/03/02/21-vue3项目开发/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh_CN" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2023/01/17/20-%E8%B7%A8%E5%B9%B3%E5%8F%B0%E6%96%87%E6%A1%A3/" rel="prev" title="文档的在线预览和上传下载">
      <i class="fa fa-chevron-left"></i> 文档的在线预览和上传下载
    </a></div>
      <div class="post-nav-item">
    <a href="/2023/08/14/22-%E4%BD%8E%E4%BB%A3%E7%A0%81%E5%B9%B3%E5%8F%B0/" rel="next" title="低代码平台开发">
      低代码平台开发 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA"><span class="nav-number">1.</span> <span class="nav-text">一、项目构建</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7"><span class="nav-number">1.1.</span> <span class="nav-text">构建工具</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#CSS-%E6%A0%B7%E5%BC%8F"><span class="nav-number">1.2.</span> <span class="nav-text">CSS 样式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Route-%E8%B7%AF%E7%94%B1"><span class="nav-number">1.3.</span> <span class="nav-text">Route 路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Pinia-%E7%8A%B6%E6%80%81"><span class="nav-number">1.4.</span> <span class="nav-text">Pinia 状态</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#axios-%E9%80%9A%E4%BF%A1"><span class="nav-number">1.5.</span> <span class="nav-text">axios 通信</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E7%89%88%E6%9C%AC%E4%BC%98%E5%8C%96"><span class="nav-number">2.</span> <span class="nav-text">二、版本优化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8A%9F%E8%83%BD%E4%BC%98%E5%8C%96"><span class="nav-number">2.1.</span> <span class="nav-text">功能优化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%93%8D%E5%BA%94%E5%BC%8F%E5%BC%80%E5%8F%91"><span class="nav-number">2.2.</span> <span class="nav-text">响应式开发</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Hooks-%E5%B7%A5%E5%85%B7"><span class="nav-number">2.3.</span> <span class="nav-text">Hooks 工具</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Tailwind-%E6%A0%B7%E5%BC%8F"><span class="nav-number">2.4.</span> <span class="nav-text">Tailwind 样式</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91"><span class="nav-number">3.</span> <span class="nav-text">二、组件开发</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E6%B3%A8%E5%86%8C"><span class="nav-number">3.1.</span> <span class="nav-text">组件注册</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E6%8B%9F%E6%95%B0%E6%8D%AE"><span class="nav-number">3.2.</span> <span class="nav-text">模拟数据</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90"><span class="nav-number">3.3.</span> <span class="nav-text">静态资源</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BA%8B%E4%BB%B6%E8%81%94%E5%8A%A8"><span class="nav-number">3.4.</span> <span class="nav-text">事件联动</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1"><span class="nav-number">4.</span> <span class="nav-text">三、组件通信</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#props-x2F-expose"><span class="nav-number">4.1.</span> <span class="nav-text">props&#x2F;expose</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#emit"><span class="nav-number">4.2.</span> <span class="nav-text">$emit</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#attrs"><span class="nav-number">4.3.</span> <span class="nav-text">$attrs</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#slot"><span class="nav-number">4.4.</span> <span class="nav-text">slot</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#v-model"><span class="nav-number">4.5.</span> <span class="nav-text">v-model</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#provide-x2F-inject"><span class="nav-number">4.6.</span> <span class="nav-text">provide&#x2F;inject</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E6%A1%88%E4%BE%8B"><span class="nav-number">5.</span> <span class="nav-text">四、案例</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="chuangges" src="" data-original="/images/chuang.png">
  <p class="site-author-name" itemprop="name">chuangges</p>
  <div class="site-description" itemprop="description">chuangge's blog.</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/chuangges" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;chuangges" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/yourname" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;yourname" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-stack-overflow fa-fw"></i>StackOverflow</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://juejin.im/" title="https:&#x2F;&#x2F;juejin.im&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">掘金</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.nowcoder.com/" title="https:&#x2F;&#x2F;www.nowcoder.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">牛客网</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.docschina.org/" title="https:&#x2F;&#x2F;www.docschina.org&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">印记中文</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://tool.lu/" title="http:&#x2F;&#x2F;tool.lu&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">在线工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tinypng.com/" title="https:&#x2F;&#x2F;tinypng.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片压缩</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://bigjpg.com/" title="https:&#x2F;&#x2F;bigjpg.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片放大</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tool.chinaz.com/" title="https:&#x2F;&#x2F;tool.chinaz.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">站长工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://learn-anything.xyz/" title="https:&#x2F;&#x2F;learn-anything.xyz&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Learn-Anything</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://stackoverflow.com/" title="https:&#x2F;&#x2F;stackoverflow.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Stack-Overflow</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">chuangge</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">1m</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">15:14</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","model":{"jsonPath":"/live2dw/assets/tororo.model.json"},"display":{"position":"left","width":180,"height":360},"mobile":{"show":false},"react":{"opacityDefault":1,"opacityOnHover":1},"log":false,"tagMode":false});</script>
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(e){e.imageLazyLoadSetting.processImages=t;var n=e.imageLazyLoadSetting.isSPA,i=e.imageLazyLoadSetting.preloadRatio||1,r=o();function o(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){n&&(r=o());for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(e.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];e=function(){r=r.filter(function(t){return o!==t})},(t=o).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,t.removeAttribute("data-original"),e&&e()},t.src!==i&&(n.src=i))}()}function a(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",a),e.addEventListener("resize",a),e.addEventListener("orientationchange",a)}(this);</script></body>
</html>
